module ysyx_210191(
    input         clock,
    input         reset,
    input         io_interrupt,
    input         io_master_awready,
    output        io_master_awvalid,
    output [31:0] io_master_awaddr,
    output [3:0]  io_master_awid,
    output [7:0]  io_master_awlen,
    output [2:0]  io_master_awsize,
    output [1:0]  io_master_awburst,
    input         io_master_wready,
    output        io_master_wvalid,
    output [63:0] io_master_wdata,
    output [7:0]  io_master_wstrb,
    output        io_master_wlast,
    output        io_master_bready,
    input         io_master_bvalid,
    input  [1:0]  io_master_bresp,
    input  [3:0]  io_master_bid,
    input         io_master_arready,
    output        io_master_arvalid,
    output [31:0] io_master_araddr,
    output [3:0]  io_master_arid,
    output [7:0]  io_master_arlen,
    output [2:0]  io_master_arsize,
    output [1:0]  io_master_arburst,
    output        io_master_rready,
    input         io_master_rvalid,
    input  [1:0]  io_master_rresp,
    input  [63:0] io_master_rdata,
    input         io_master_rlast,
    input  [3:0]  io_master_rid,
    output        io_slave_awready,
    input         io_slave_awvalid,
    input  [31:0] io_slave_awaddr,
    input  [3:0]  io_slave_awid,
    input  [7:0]  io_slave_awlen,
    input  [2:0]  io_slave_awsize,
    input  [1:0]  io_slave_awburst,
    output        io_slave_wready,
    input         io_slave_wvalid,
    input  [63:0] io_slave_wdata,
    input  [7:0]  io_slave_wstrb,
    input         io_slave_wlast,
    input         io_slave_bready,
    output        io_slave_bvalid,
    output [1:0]  io_slave_bresp,
    output [3:0]  io_slave_bid,
    output        io_slave_arready,
    input         io_slave_arvalid,
    input  [31:0] io_slave_araddr,
    input  [3:0]  io_slave_arid,
    input  [7:0]  io_slave_arlen,
    input  [2:0]  io_slave_arsize,
    input  [1:0]  io_slave_arburst,
    input         io_slave_rready,
    output        io_slave_rvalid,
    output [1:0]  io_slave_rresp,
    output [63:0] io_slave_rdata,
    output        io_slave_rlast,
    output [3:0]  io_slave_rid
);

module ysyx_210191_ALU(
    input [63:0] data1,
    input [63:0] data2,
    input [16:0] ALUControl,

    output reg [63:0] res
);

    wire [63:0] sum = data1 + data2;
    wire [63:0] sub = data1 - data2;
    wire [63:0] sll = data1 << data2[5:0];
    wire [31:0] sllw = data1 << data2[4:0];
    wire [63:0] srl = data1 >> data2[5:0];
    wire [31:0] srlw = data1[31:0] >> data2[4:0];
    wire [63:0] sra = $signed(data1) >>> data2[5:0];
    wire [31:0] sraw = $signed(data1[31:0]) >>> data2[4:0];
    wire is_less = data1[63] == 0 ? (data2[63] == 1 ? 0 : data1 < data2) : (data2[63] == 0 ? 1 : data1 < data2);

    always @(*) begin
        case(ALUControl)
            17'b10000000000000000: begin //add
                res = sum;
            end
            17'b01000000000000000 : begin //addw
                res = {{32{sum[31]}}, sum[31:0]};
            end
            17'b00100000000000000: begin //sub
                res = sub;
            end
            17'b00010000000000000: begin //subw
                res = {{32{sub[31]}}, sub[31:0]};
            end
            17'b00001000000000000: begin //lui
                res = {data2[51:0], 12'd0};
            end
            17'b00000100000000000: begin //auipc
                res = sum;
            end
            17'b00000010000000000: begin //xor
                res = data1 ^ data2;
            end
            17'b00000001000000000: begin //or
                res = data1 | data2;
            end
            17'b00000000100000000: begin //and
                res = data1 & data2;
            end
            17'b00000000010000000: begin //slt
                res = (data1 < data2) ? 64'd1 : 64'd0;
            end
            17'b00000000001000000: begin //sll
                res = sll;
            end
            17'b00000000000100000: begin //sllw
                res = {{32{sllw[31]}}, sllw[31:0]};
            end
            17'b00000000000010000: begin //srl
                res = srl;
            end
            17'b00000000000001000: begin //srlw
                res = {{32{srlw[31]}}, srlw[31:0]};
            end
            17'b00000000000000100: begin //sra
                res = sra;
            end
            17'b00000000000000010: begin //sra
                res = {{32{sraw[31]}}, sraw[31:0]};
            end
            17'b00000000000000001: begin //sra
                res = is_less ? 64'd1 : 64'd0;
            end
            default : begin
                res = 64'd0;
            end
        endcase
    end

endmodule
`define AXI_BURST_TYPE_FIXED                                2'b00
`define AXI_BURST_TYPE_INCR                                 2'b01
`define AXI_BURST_TYPE_WRAP                                 2'b10
// Access permissions
`define AXI_PROT_UNPRIVILEGED_ACCESS                        3'b000
`define AXI_PROT_PRIVILEGED_ACCESS                          3'b001
`define AXI_PROT_SECURE_ACCESS                              3'b000
`define AXI_PROT_NON_SECURE_ACCESS                          3'b010
`define AXI_PROT_DATA_ACCESS                                3'b000
`define AXI_PROT_INSTRUCTION_ACCESS                         3'b100
// Memory types (AR)
`define AXI_ARCACHE_DEVICE_NON_BUFFERABLE                   4'b0000
`define AXI_ARCACHE_DEVICE_BUFFERABLE                       4'b0001
`define AXI_ARCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE     4'b0010
`define AXI_ARCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE         4'b0011
`define AXI_ARCACHE_WRITE_THROUGH_NO_ALLOCATE               4'b1010
`define AXI_ARCACHE_WRITE_THROUGH_READ_ALLOCATE             4'b1110
`define AXI_ARCACHE_WRITE_THROUGH_WRITE_ALLOCATE            4'b1010
`define AXI_ARCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE   4'b1110
`define AXI_ARCACHE_WRITE_BACK_NO_ALLOCATE                  4'b1011
`define AXI_ARCACHE_WRITE_BACK_READ_ALLOCATE                4'b1111
`define AXI_ARCACHE_WRITE_BACK_WRITE_ALLOCATE               4'b1011
`define AXI_ARCACHE_WRITE_BACK_READ_AND_WRITE_ALLOCATE      4'b1111
// Memory types (AW)
`define AXI_AWCACHE_DEVICE_NON_BUFFERABLE                   4'b0000
`define AXI_AWCACHE_DEVICE_BUFFERABLE                       4'b0001
`define AXI_AWCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE     4'b0010
`define AXI_AWCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE         4'b0011
`define AXI_AWCACHE_WRITE_THROUGH_NO_ALLOCATE               4'b0110
`define AXI_AWCACHE_WRITE_THROUGH_READ_ALLOCATE             4'b0110
`define AXI_AWCACHE_WRITE_THROUGH_WRITE_ALLOCATE            4'b1110
`define AXI_AWCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE   4'b1110
`define AXI_AWCACHE_WRITE_BACK_NO_ALLOCATE                  4'b0111
`define AXI_AWCACHE_WRITE_BACK_READ_ALLOCATE                4'b0111
`define AXI_AWCACHE_WRITE_BACK_WRITE_ALLOCATE               4'b1111
`define AXI_AWCACHE_WRITE_BACK_READ_AND_WRITE_ALLOCATE      4'b1111

`define AXI_SIZE_BYTES_1                                    3'b000
`define AXI_SIZE_BYTES_2                                    3'b001
`define AXI_SIZE_BYTES_4                                    3'b010
`define AXI_SIZE_BYTES_8                                    3'b011
`define AXI_SIZE_BYTES_16                                   3'b100
`define AXI_SIZE_BYTES_32                                   3'b101
`define AXI_SIZE_BYTES_64                                   3'b110
`define AXI_SIZE_BYTES_128                                  3'b111

module ysyx_210191_axi4_crtl(
    input ACLK,
    input ARESETn,
    input flush,

    input inst_r_ena,
    input [63:0] inst_addr,
    output reg [31:0] inst_r,
    input data_r_ena,
    input data_w_ena,
    input [63:0] data_addr,
    input [63:0] data_w,
    input [63:0] data_w_addr,
    input [7:0] data_w_mask,
    input wlast_i,
    output reg [63:0] data_r,

    output [3:0] ARID,
    output [63:0] ARADDR,
    output [7:0] ARLEN,
    output [2:0] ARSIZE,
    output [1:0] ARBURST,
    output [1:0] ARLOCK,
    output [3:0] ARCACHE,
    output [2:0] ARPROT,
    output [3:0] ARQOS,
    output [3:0] ARREGION,
    output ARVALID,
    input ARREADY,

    input [3:0] RID,
    input [63:0] RDATA,
    input RVALID,
    output RREADY,
    input RLAST,
    input [1:0] RRESP,

    output [3:0] AWID,
    output [63:0] AWADDR,
    output [7:0] AWLEN,
    output [2:0] AWSIZE,
    output [1:0] AWBURST,
    output [1:0] AWLOCK,
    output [3:0] AWCACHE,
    output [2:0] AWPROT,
    output [3:0] AWQOS,
    output [3:0] AWREGION,
    output AWVALID,
    input AWREADY,

    output [63:0] WDATA,
    output [7:0] WSTRB,
    output WVALID,
    input WREADY,
    output WLAST,

    input [3:0] BID,
    input BVALID,
    output BREADY,
    input [1:0] BRESP,

    output reg data_r_valid,
    output reg data_w_valid,
    output reg inst_r_valid
);

    parameter IDEL               = 3'b000;	//空闲
	parameter INST_SEND_RADDR    = 3'b001;	//指令cache发读地址
	parameter INST_RECEIVE_RDATA = 3'b010;	//指令cache接收读数据
	parameter DATA_SEND_RADDR    = 3'b011;	//数据cache发读地址
	parameter DATA_RECEIVE_RDATA = 3'b100;	//数据cache接收读数据
	parameter DATA_SEND_WADDR    = 3'b001;	//数据cache发写地址
	parameter DATA_SEND_WDATA    = 3'b010;	//数据cache发写数据
	parameter DATA_RECEIVE_B     = 3'b011;	//数据cache写响应

    wire ar_hs = ARREADY & ARVALID;
    wire r_hs = RREADY & RVALID;
    wire aw_hs = AWREADY & AWVALID;
    wire w_hs = WREADY & WVALID;
    wire b_hs = BREADY & BVALID;
    wire r_done = r_hs & RLAST;
    wire w_done = w_hs & WLAST;
	
	reg [2:0] axi_read_state;
    reg [2:0] axi_write_state;

    always @(posedge ACLK) begin
        if(ARESETn) begin
            axi_read_state <= 3'b000;
            data_r <= 64'd0;
            data_r_valid <= 1'b0;
            inst_r_valid <= 1'b0;
            inst_r <= 32'd0;
        end else begin
            case(axi_read_state)
                IDEL: begin
                    data_r <= 64'd0;
                    inst_r <= 32'd0;
                    if(flush) begin
                        axi_read_state <= IDEL;
                    end else if(inst_r_ena) begin
                        axi_read_state <= INST_SEND_RADDR;
                        inst_r_valid <= 1'b0;
                        data_r_valid <= 1'b0;
                    end else if(data_r_ena) begin
                        axi_read_state <= DATA_SEND_RADDR;
                        inst_r_valid <= 1'b0;
                        data_r_valid <= 1'b0;
                    end
                end
                INST_SEND_RADDR : begin
                    if(ar_hs) begin
                        axi_read_state <= INST_RECEIVE_RDATA;
                    end
                end
                INST_RECEIVE_RDATA : begin
                    if(r_done) begin
                        axi_read_state <= IDEL;
                        inst_r <= inst_addr[2] ? RDATA[63:32] : RDATA[31:0];
                        inst_r_valid <= 1'b1;
                    end
                end
                DATA_SEND_RADDR : begin
                    if(ar_hs) begin
                        axi_read_state <= DATA_RECEIVE_RDATA;
                    end
                end
                DATA_RECEIVE_RDATA : begin
                    if(r_done) begin
                        axi_read_state <= IDEL;
                        data_r <= RDATA;
                        data_r_valid <= 1'b1;
                    end
                end
                default : begin
                    
                end
            endcase
        end
    end

    always @(posedge ACLK) begin
        if(ARESETn) begin
            axi_write_state <= 3'b000;
        end else begin
            case(axi_write_state)
                IDEL: begin
                    data_w_valid <= 1'b0;
                    if(flush) begin
                        axi_write_state <= IDEL;
                    end else if(data_w_ena) begin
                        axi_write_state <= DATA_SEND_WADDR;
                    end
                end
                DATA_SEND_WADDR : begin
                    if(aw_hs) begin
                        axi_write_state <= DATA_SEND_WDATA;
                    end
                end
                DATA_SEND_WDATA : begin
                    if(w_done) begin
                        axi_write_state <= DATA_RECEIVE_B;
                    end
                end
                DATA_RECEIVE_B : begin
                    if(b_hs) begin
                        axi_write_state <= IDEL;
                        data_w_valid <= 1'b1;
                    end
                end
                default : begin
                    
                end
            endcase    
        end
    end
    ///////////////////////////////////////////////////
    wire aligned = data_addr[2:0] == 0;
    wire size_b             = 1'b0;
    wire size_h             = 1'b0;
    wire size_w             = 1'b0;
    wire size_d             = 1'b1;
    wire [3:0] addr_op1     = {{1{1'b0}}, data_addr[2:0]};
    wire [3:0] addr_op2     = ({4{size_b}} & {4'b0})
                                | ({4{size_h}} & {4'b1})
                                | ({4{size_w}} & {4'b11})
                                | ({4{size_d}} & {4'b111})
                                ;
    wire [3:0] addr_end     = addr_op1 + addr_op2;
    wire overstep           = addr_end[3] != 0;
    wire [7:0] axi_len      = aligned ? 0 : {{7{1'b0}}, overstep};

    wire [5:0] aligned_offset_l    = {{3{1'b0}}, {data_addr[2:0]}} << 3;
    wire [5:0] aligned_offset_h    = 64 - aligned_offset_l;
    wire [127:0] mask                  = (({128{size_b}} & {{120{1'b0}}, 8'hff})
                                                    | ({128{size_h}} & {{112{1'b0}}, 16'hffff})
                                                    | ({128{size_w}} & {{96{1'b0}}, 32'hffffffff})
                                                    | ({128{size_d}} & {{64{1'b0}}, 64'hffffffff_ffffffff})
                                                    ) << aligned_offset_l;
    wire [63:0] mask_l            = mask[63:0];
    wire [63:0] mask_h            = mask[127:63];

    reg [7:0] len;
    wire len_reset      = ARESETn | (b_hs & axi_write_state == IDEL);
    wire len_incr_en    = (len != axi_len) & (w_hs | r_hs);
    always @(posedge ACLK) begin
        if (len_reset) begin
            len <= 0;
        end
        else if (len_incr_en) begin
            len <= len + 1;
        end
    end

    wire [63:0] axi_r_data_l  = (RDATA & mask_l) >> aligned_offset_l;
    wire [63:0] axi_r_data_h  = (RDATA & mask_h) << aligned_offset_h;

    generate
        for (genvar i = 0; i < 1; i += 1) begin
            always @(posedge ACLK) begin
                if (ARESETn) begin
                    data_r[i*64+:64] <= 0;
                end
                else if (r_hs) begin
                    if (~aligned & overstep) begin
                        if (len[0]) begin
                            data_r[63:0] <= data_r[63:0] | axi_r_data_h;
                        end
                        else begin
                            data_r[63:0] <= axi_r_data_l;
                        end
                    end
                    else if (len == i) begin
                        data_r[i*64+:64] <= axi_r_data_l;
                    end
                end
            end
        end
    endgenerate
    ///////////////////////////////////////////////////

    assign ARID = 4'b0000;
    assign ARADDR = (axi_read_state == INST_SEND_RADDR || axi_read_state == INST_RECEIVE_RDATA) ? {inst_addr[63:3], {3{1'b0}}} : ((axi_read_state == DATA_SEND_RADDR || axi_read_state == DATA_RECEIVE_RDATA) ? {data_addr[63:3], {3{1'b0}}} : 64'd0);
    assign ARVALID = (axi_read_state == INST_SEND_RADDR || axi_read_state == DATA_SEND_RADDR) ? 1'b1 : 1'b0;
    assign ARLEN = 8'd0;
    assign ARSIZE = `AXI_SIZE_BYTES_8;
    assign ARBURST = `AXI_BURST_TYPE_INCR;
    assign ARLOCK = 1'b0;
    assign ARCACHE = `AXI_ARCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE;
    assign ARPROT = `AXI_PROT_UNPRIVILEGED_ACCESS;
    assign ARQOS = 4'b0000;
    assign ARREGION = 4'b0000;

    assign RREADY = (axi_read_state == INST_RECEIVE_RDATA || axi_read_state == DATA_RECEIVE_RDATA) ? 1'b1 : 1'b0;

    assign AWID = 4'b0000;
    assign AWADDR = (axi_write_state == DATA_SEND_WADDR || axi_write_state == DATA_SEND_WDATA) ? {data_w_addr[63:3], {3{1'b0}}} : 64'd0;
    assign AWLEN = 8'd0;
    assign AWSIZE = `AXI_SIZE_BYTES_8;
    assign AWBURST = `AXI_BURST_TYPE_INCR;
    assign AWLOCK = 1'b0;
    assign AWCACHE = `AXI_AWCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE;
    assign AWPROT = `AXI_PROT_UNPRIVILEGED_ACCESS;
    assign AWQOS = 4'b0000;
    assign AWREGION = 4'b0000;
    assign AWVALID = (axi_write_state == DATA_SEND_WADDR) ? 1'b1 : 1'b0;

    assign WDATA = (axi_write_state == DATA_SEND_WDATA) ? data_w : 64'd0;
    assign WSTRB = (axi_write_state == DATA_SEND_WDATA) ? data_w_mask : 8'b00000000;
    assign WVALID = (axi_write_state == DATA_SEND_WDATA) ? 1'b1 : 1'b0;
    assign WLAST = 1'b1;

    assign BREADY = (axi_write_state == DATA_RECEIVE_B) ? 1'b1 : 1'b0;
endmodulemodule CLINT(
    input clk,
    input reset,
    input [63:0] wdata,
    input mtimecmp_ena,
    input mtime_ena,

    output mtime_int,
    output [63:0] mtime_data,
    output [63:0] mtimecmp_data
);

    reg [63:0] mtime;
    reg [63:0] mtimecmp;

    always @(posedge clk) begin
        if(reset) begin
            mtime <= 64'd0;
        end else if(mtime_ena) begin
            mtime <= wdata;
        end else begin
            mtime <= mtime + 1;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mtimecmp <= 64'd0;
        end else if(mtimecmp_ena) begin
            mtimecmp <= wdata;
        end
    end

    assign mtime_int = mtime != 0 && mtimecmp != 0 ? mtime >= mtimecmp : 1'b0;
    assign mtime_data = mtime;
    assign mtimecmp_data = mtimecmp;

endmodulemodule csr(
    input clk,
    input reset,
    input [63:0] csr_wdata,
    input [11:0] i_csr,
    input write_ena,
    input except_ena,
    //input ext_int,
    input [63:0] i_addr,
    input [63:0] i_badvaddr,
    input [63:0] i_excode,
    input [31:0] badinst,
    input ret,
    input mtime_int,
    output reg [63:0] o_csr_data,
    output [63:0] mtvec_pc,
    output [63:0] epc,
    output [63:0] mstatus_data,
    output [63:0] mtvec_data,
    output [63:0] mepc_data,
    output [63:0] mcause_data,
    output [63:0] mie_data,
    output [63:0] mip_data,
    output [63:0] mscratch_data,
    output [63:0] sstatus_data
);

    wire ext_int = 1'b0;
    reg [63:0] mcpuid;
    reg [63:0] mimpid;
    reg [63:0] mhartid;
    reg [63:0] mstatus;
    reg [63:0] mtvec;
    reg [63:0] mepc;
    reg [63:0] mcause;
    reg [63:0] mie;
    reg [63:0] mip;
    reg [63:0] mtval;
    reg [63:0] mscratch;
    reg [63:0] mcycle;

    assign mstatus_data = mstatus;
    assign mtvec_data = mtvec;
    assign mepc_data = mepc;
    assign mcause_data = mcause;
    assign mie_data = mie;
    assign mip_data = mip;
    assign mscratch_data = mscratch;
    assign sstatus_data = mstatus_data & 64'h80000003000DE122;
    

    always @(posedge clk) begin
        if(reset) begin
            mcpuid <= {2'b10, 36'd0, 17'b0, 1'b1, 8'd0};
        end else if(write_ena && i_csr == 12'hf00) begin
            mcpuid <= csr_wdata;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            
        end else if(write_ena && i_csr == 12'hf01) begin
            mimpid <= csr_wdata;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mhartid <= 64'd0;
        end else if(write_ena && i_csr == 12'hf10) begin
            mhartid <= csr_wdata;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mstatus <= {51'd0, 2'b11, 3'b000, 1'b0, 3'b000, 1'b0, 3'b000};
        end else if(except_ena || ext_int) begin
            mstatus <= {mstatus[63:13], 2'b11, 3'b000, mstatus[3], 3'b000, 1'b0, 3'b000};
        end else if(write_ena && i_csr == 12'h300) begin
            mstatus <= {csr_wdata[14:13] == 2'b11 || csr_wdata[16:15] == 2'b11, csr_wdata[62:0]};
        end else if(ret) begin
            mstatus <= {mstatus[63:13], 2'b00, 3'b000, 1'b1, 3'b000, mstatus[7], 3'b000};
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mtvec <= 64'd0;
        end else if(write_ena && i_csr == 12'h305) begin
            mtvec <= csr_wdata;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mepc <= 64'd0;
        end else if(except_ena) begin
            mepc <= {i_addr[63:2], 2'b00};
        end else if(write_ena && i_csr == 12'h341) begin
            mepc <= csr_wdata;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mcause <= 64'd0;
        end else if(ext_int) begin
            mcause <= {1'b1, 63'd11};
        end else if(except_ena) begin
            mcause <= i_excode;
        end else if(write_ena && i_csr == 12'h342) begin
            mcause <= csr_wdata;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mie <= {52'd0, 1'b0, 3'b000, 1'b1, 3'b000, 1'b0, 3'b000};
        end else if(write_ena && i_csr == 12'h304) begin
            mie <= csr_wdata;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mip <= {52'd0, 1'b0, 3'b000, 1'b0, 3'b000, 1'b0, 3'b000};
        end else if(write_ena && i_csr == 12'h344) begin
            mip <= csr_wdata;
        end else begin
            if(ext_int) begin
                mip[11] <= 1'b1;
            end else begin
                mip[11] <= 1'b0;
            end
            if(mtime_int) begin
                mip[7] <= 1'b1;
            end else begin
                mip[7] <= 1'b0;
            end
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mtval <= 64'd0;
        end else if(i_excode[63] == 0 &&(i_excode[62:0] == 63'd0 || i_excode[62:0] == 63'd1 || i_excode[62:0] == 63'd3 || i_excode[62:0] == 63'd4 || i_excode[62:0] == 63'd5 || i_excode[62:0] == 63'd6 || i_excode[62:0] == 63'd7)) begin
            mtval <= i_badvaddr;
        end else if(i_excode[63] == 0 && i_excode[62:0] == 63'd2) begin
            mtval <= {32'd0, badinst};
        end else begin
            mtval <= 64'd0;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            mscratch <= 64'd0;
        end else if(write_ena && i_csr == 12'h340) begin
            mscratch <= csr_wdata;
        end
    end


    always @(posedge clk) begin
        if(reset) begin
            mcycle <= 64'd0;
        end else if(write_ena && i_csr == 12'hb00) begin
            mcycle <= csr_wdata;
        end
        mcycle <= mcycle + 64'd1;
    end

    assign mtvec_pc = mtvec[1:0] == 2'b00 ? {mtvec[63:2], 2'b00} : (mcause[63] == 0 ? {mtvec[63:2], 2'b00} + mcause[62:0] >> 2 : (mcause[63] == 1 ? {mtvec[63:2], 2'b00} : 64'd0));
    assign epc = mepc;
    
    always @(i_csr) begin
        case(i_csr)
            12'hf13 : begin
                o_csr_data <= mimpid;
            end
            12'h300 : begin
                o_csr_data <= mstatus;
            end
            12'h304 : begin
                o_csr_data <= mie;
            end
            12'h305 : begin
                o_csr_data <= mtvec;
            end
            12'h340 : begin
                o_csr_data <= mscratch;
            end
            12'h341 : begin
                o_csr_data <= mepc;
            end
            12'h342 : begin
                o_csr_data <= mcause;
            end
            12'h343 : begin
                o_csr_data <= mtval;
            end
            12'h344 : begin
                o_csr_data <= mip;
            end
            12'hf14 : begin
                o_csr_data <= mhartid;
            end
            12'hb00 : begin
                o_csr_data <= mcycle;
            end
            default : begin
                
            end
        endcase
    end

endmodulemodule ctrl(
    input clk,
    input reset,
    input except_ena,
    input [63:0] mtvec_pc,
    input [63:0] epc,
    input ret,
    input stall_from_if,
    input stall_from_mem,
    input inst_r_valid,
    
    output reg [63:0] new_pc,
    output reg flush,
    output reg [5:0] stall,
    output reg keep
);

    always @(posedge clk) begin
        if(except_ena || ret) begin
            keep <= 1'b1;
        end
        if(keep == 1'b1 && inst_r_valid == 1'b1) begin
            keep <= 1'b0;
        end
    end

    always @(*) begin
        if(reset) begin
            stall = 6'b000000;
            flush = 1'b0;
            new_pc = 64'd0;
        end else if(except_ena) begin
            new_pc = mtvec_pc;
            stall = 6'b000000;
            flush = 1'b1;
        end else if(ret) begin
            new_pc = epc;
            flush = 1'b1;
            stall = 6'b000000;
        end else if(stall_from_mem) begin
            new_pc = 64'd0;
            flush = 1'b0;
            stall = 6'b011111;
        end else if(stall_from_if) begin
            new_pc = 64'd0;
            flush = 1'b0;
            stall = 6'b000111;
        end else begin
            stall = 6'b000000;
            flush = 1'b0;
            new_pc = 64'd0;
        end
    end
    
endmodulemodule decode(
    input clk,
    input reset,

    input [31:0] inst,
    input [63:0] inst_addr,

    input [63:0] rdata1,
    input [63:0] rdata2,

    input [4:0] exe_out_addr,
    input [63:0] exe_out,
    input [4:0] mem_out_addr,
    input [63:0] mem_out_1,
    input [63:0] mem_out_2,
    input exe_write_to_regfile,
    input mem_write_to_regfile,
    input exe_mem_to_regfile,
    input mem_mem_to_regfile,
    input [63:0] i_excode,
    input i_except_ena,
    //input wb_write_to_regfile,

    output write_to_mem,
    output write_to_regfile,
    output [4:0] reg_addr,
    output [16:0] ALUControl,
    output [63:0] b_j_pc,
    output pcsource,
    output [63:0] sext_imm,
    output aluimm,
    output [63:0] data1,
    output [63:0] data2,
    output is_jump,
    output [3:0] mem_control,
    output mem_to_regfile,
    output [11:0] csr,
    output [63:0] csr_wdata,
    output [2:0] csr_control,
    output [63:0] o_excode,
    output o_except_ena,
    output flush_if_id,
    output ret,
    output shift,
    output [63:0] shamt_ext
);
////////////////////////////////////////////////////////U指令
    wire inst_lui;
    wire inst_auipc;
////////////////////////////////////////////////////////
    wire inst_jal;
    wire inst_jalr;
////////////////////////////////////////////////////////B指令
    wire inst_beq;
    wire inst_bne;
    wire inst_blt;
    wire inst_bge;
    wire inst_bltu;
    wire inst_bgeu;
////////////////////////////////////////////////////////I指令
    wire inst_lb;
    wire inst_lh;
    wire inst_lw;
    wire inst_lbu;
    wire inst_lhu;
    wire inst_lwu;
    wire inst_ld;

    wire inst_addi;
    wire inst_addiw;
    wire inst_slti;
    wire inst_sltiu;
    wire inst_xori;
    wire inst_ori;
    wire inst_andi;
    wire inst_slli;
    wire inst_srli;
    wire inst_srai;

    wire inst_fence;
    wire inst_fence_i;
    wire inst_ecall;
    wire inst_ebreak;
    wire inst_csrrw;
    wire inst_csrrs;
    wire inst_csrrc;
    wire inst_csrrwi;
    wire inst_csrrsi;
    wire inst_csrrci;

    wire inst_sret;
    wire inst_mret;
    wire inst_wfi;
    wire inst_sfence_vma;
////////////////////////////////////////////////////////S指令
    wire inst_sb;
    wire inst_sh;
    wire inst_sw;
    wire inst_sd;
////////////////////////////////////////////////////////R指令
    wire inst_add;
    wire inst_addw;
    wire inst_sub;
    wire inst_subw;
    wire inst_sll;
    wire inst_slt;
    wire inst_sltu;
    wire inst_sllw;
    wire inst_slliw;
    wire inst_xor;
    wire inst_srl;
    wire inst_srlw;
    wire inst_srliw;
    wire inst_sra;
    wire inst_sraw;
    wire inst_sraiw;
    wire inst_or;
    wire inst_and;
////////////////////////////////////////////////////////
    wire shift_op;
    wire arithmetic_op;
    wire logic_op;
    wire compare_op;
    wire branch_op;
    wire synch_op;
    wire jumplink_op;
    wire environment_op;
    wire CSR_op;
    wire load_op;
    wire store_op;
////////////////////////////////////////////////////////
    wire [6:0] op;
    wire [4:0] rd;
    wire [4:0] rs1;
    wire [4:0] rs2;
    wire [2:0] func_3;
    wire [6:0] func_7;
    wire [5:0] func_6;
    wire [11:0] imm_11_0;
    wire [11:0] imm_11_5_4_0;

    assign op = inst[6:0];
    assign rd = inst[11:7];
    assign rs1 = inst[19:15];
    assign rs2 = inst[24:20];
    assign func_3 = inst[14:12];
    assign func_7 = inst[31:25];
    assign func_6 = inst[31:26];
    assign imm_11_0 = inst[31:20];
    assign imm_11_5_4_0 = {inst[31:25], inst[11:7]};
    assign csr = inst[31:20];
////////////////////////////////////////////////////////
    wire inst_decode;

    assign inst_decode = 
     inst_lui   | inst_auipc   |
     inst_jal   | inst_jalr    |
     inst_beq   | inst_bne     | inst_blt   | inst_bge    | inst_bltu  |  inst_bgeu |
     inst_lb    | inst_lh      | inst_lw    | inst_lbu    | inst_lhu   |  inst_lwu  | inst_ld    |
     inst_sb    | inst_sh      | inst_sw    | inst_sd     |
     inst_addi  | inst_slti    | inst_sltiu | inst_xori   | inst_ori   | inst_andi  | inst_slli  | inst_srli   | inst_srai    | inst_addiw  |
     inst_add   | inst_sub     | inst_sll   | inst_slt    | inst_sltu  | inst_xor   | inst_srl   | inst_sra    | inst_or      | inst_and    | inst_sllw | inst_slliw | inst_srlw | inst_srliw | inst_sraw | inst_sraiw | inst_addw | inst_subw |
     inst_fence | inst_fence_i | inst_ecall | inst_ebreak | inst_csrrw | inst_csrrs | inst_csrrc | inst_csrrwi | inst_csrrsi  | inst_csrrci |
     inst_sret  | inst_mret    | inst_wfi   | inst_sfence_vma;

    assign inst_lui = op == 7'b0110111;
    assign inst_auipc = op == 7'b0010111;

    assign inst_jal = op == 7'b1101111;
    assign inst_jalr = op == 7'b1100111;

    assign inst_beq = op == 7'b1100011 && func_3 == 3'b000;
    assign inst_bne = op == 7'b1100011 && func_3 == 3'b001;
    assign inst_blt = op == 7'b1100011 && func_3 == 3'b100;
    assign inst_bge = op == 7'b1100011 && func_3 == 3'b101;
    assign inst_bltu = op == 7'b1100011 && func_3 == 3'b110;
    assign inst_bgeu = op == 7'b1100011 && func_3 == 3'b111;

    assign inst_lb = op == 7'b0000011 && func_3 == 3'b000;
    assign inst_lh = op == 7'b0000011 && func_3 == 3'b001;
    assign inst_lw = op == 7'b0000011 && func_3 == 3'b010;
    assign inst_lbu = op == 7'b0000011 && func_3 == 3'b100;
    assign inst_lhu = op == 7'b0000011 && func_3 == 3'b101;
    assign inst_lwu = op == 7'b0000011 && func_3 == 3'b110;
    assign inst_ld = op == 7'b0000011 && func_3 == 3'b011;

    assign inst_sb = op == 7'b0100011 && func_3 == 3'b000;
    assign inst_sh = op == 7'b0100011 && func_3 == 3'b001;
    assign inst_sw = op == 7'b0100011 && func_3 == 3'b010;
    assign inst_sd = op == 7'b0100011 && func_3 == 3'b011;

    assign inst_addi = op == 7'b0010011 && func_3 == 3'b000;
    assign inst_addiw = op == 7'b0011011 && func_3 == 3'b000;
    assign inst_slti = op == 7'b0010011 && func_3 == 3'b010;
    assign inst_sltiu = op == 7'b0010011 && func_3 == 3'b011;
    assign inst_xori = op == 7'b0010011 && func_3 == 3'b100;
    assign inst_ori = op == 7'b0010011 && func_3 == 3'b110;
    assign inst_andi = op == 7'b0010011 && func_3 == 3'b111;
    assign inst_slli = op == 7'b0010011 && func_3 == 3'b001 && func_6 == 6'b000000;
    assign inst_slliw = op == 7'b0011011 && func_3 == 3'b001 && func_6 == 6'b000000;
    assign inst_srli = op == 7'b0010011 && func_3 == 3'b101 && func_6 == 6'b000000;
    assign inst_srliw = op == 7'b0011011 && func_3 == 3'b101 && func_6 == 6'b000000;
    assign inst_srai = op == 7'b0010011 && func_3 == 3'b101 && func_6 == 6'b010000;
    assign inst_sraiw = op == 7'b0011011 && func_3 == 3'b101 && func_6 == 6'b010000;
    
    assign inst_add = op == 7'b0110011 && func_3 == 3'b000 && func_7 == 7'b0000000;
    assign inst_addw = op == 7'b0111011 && func_3 == 3'b000 && func_7 == 7'b0000000;
    assign inst_sub = op == 7'b0110011 && func_3 == 3'b000 && func_7 == 7'b0100000;
    assign inst_subw = op == 7'b0111011 && func_3 == 3'b000 && func_7 == 7'b0100000;
    assign inst_sll = op == 7'b0110011 && func_3 == 3'b001 && func_7 == 7'b0000000;
    assign inst_sllw = op == 7'b0111011 && func_3 == 3'b001 && func_7 == 7'b0000000;
    assign inst_slt = op == 7'b0110011 && func_3 == 3'b010 && func_7 == 7'b0000000;
    assign inst_sltu = op == 7'b0110011 && func_3 == 3'b011 && func_7 == 7'b0000000;
    assign inst_xor = op == 7'b0110011 && func_3 == 3'b100 && func_7 == 7'b0000000;
    assign inst_srl = op == 7'b0110011 && func_3 == 3'b101 && func_7 == 7'b0000000;
    assign inst_srlw = op == 7'b0111011 && func_3 == 3'b101 && func_7 == 7'b0000000;
    assign inst_sra = op == 7'b0110011 && func_3 == 3'b101 && func_7 == 7'b0100000;
    assign inst_sraw = op == 7'b0111011 && func_3 == 3'b101 && func_7 == 7'b0100000;
    assign inst_or = op == 7'b0110011 && func_3 == 3'b110 && func_7 == 7'b0000000;
    assign inst_and = op == 7'b0110011 && func_3 == 3'b111 && func_7 == 7'b0000000;

    assign inst_fence = op == 7'b0001111 && func_3 == 3'b000;
    assign inst_fence_i = op == 7'b0001111 && func_3 == 3'b001;

    assign inst_ecall = op == 7'b1110011 && func_3 == 3'b000 && imm_11_0 == 12'b000000000000;
    assign inst_ebreak = op == 7'b1110011 && func_3 == 3'b000 && imm_11_0 == 12'b000000000001;

    assign inst_csrrw = op == 7'b1110011 && func_3 == 3'b001;
    assign inst_csrrs = op == 7'b1110011 && func_3 == 3'b010;
    assign inst_csrrc = op == 7'b1110011 && func_3 == 3'b011;
    assign inst_csrrwi = op == 7'b1110011 && func_3 == 3'b101;
    assign inst_csrrsi = op == 7'b1110011 && func_3 == 3'b110;
    assign inst_csrrci = op == 7'b1110011 && func_3 == 3'b111;

    assign inst_sret = op == 7'b1110011 && func_7 == 7'b0001000 && rs2 == 5'b00010;
    assign inst_mret = op == 7'b1110011 && func_7 == 7'b0011000 && rs2 == 5'b00010;
    assign inst_wfi = op == 7'b1110011 && func_7 == 7'b0001000 && rs2 == 5'b00101;
    assign inst_sfence_vma = op == 7'b1110011 && func_7 == 7'b0001001;

    assign shift_op       = inst_sll   | inst_slli  | inst_srl   | inst_srli   | inst_sra    | inst_srai | inst_sllw | inst_slliw | inst_srlw | inst_srliw | inst_sraw | inst_sraiw;
    assign arithmetic_op  = inst_add   | inst_addi  | inst_sub   | inst_lui    | inst_auipc  | inst_addw | inst_subw | inst_addiw;
    assign logic_op       = inst_xor   | inst_xori  | inst_or    | inst_ori    | inst_and    | inst_andi;
    assign compare_op     = inst_slt   | inst_slti  | inst_sltu  | inst_sltiu;
    assign branch_op      = inst_beq   | inst_bne   | inst_blt   | inst_bge    | inst_bltu   | inst_bgeu;
    assign jumplink_op    = inst_jal   | inst_jalr;
    assign synch_op       = inst_fence | inst_fence_i;
    assign environment_op = inst_ecall | inst_ebreak;
    assign CSR_op         = inst_csrrw | inst_csrrs | inst_csrrc | inst_csrrwi | inst_csrrsi | inst_csrrci;
    assign load_op        = inst_lb    | inst_lh    | inst_lbu   | inst_lhu    | inst_lw     | inst_lwu  | inst_ld;
    assign store_op       = inst_sb    | inst_sh    | inst_sw    | inst_sd;
////////////////////////////////////////////////////////
    assign write_to_mem     = inst_sb    | inst_sh     | inst_sw   | inst_sd;
    assign write_to_regfile = inst_sll   | inst_slli   | inst_srl  | inst_srli  | inst_srai | inst_add   | inst_addi   | inst_sub   | inst_lui   |
                              inst_auipc | inst_xor    | inst_xori | inst_or    | inst_ori  | inst_and   | inst_andi   | inst_slt   | inst_slti  |
                              inst_sltu  | inst_sltiu  | inst_jalr | inst_lb    | inst_lh   | inst_lbu   | inst_lw     | inst_sllw  | inst_srlw  |
                              inst_slliw | inst_srliw  | inst_sraw | inst_sraiw | inst_addw | inst_addiw | inst_subw   | inst_lwu   | inst_ld    |
                              inst_csrrw | inst_csrrwi | inst_jal  | inst_lhu   | inst_sra  | inst_csrrc | inst_csrrci | inst_csrrs | inst_csrrsi;
    assign reg_addr = rd;
////////////////////////////////////////////////////////控制寄存器堆
    //wire [63:0] rdata1;
    //wire [63:0] rdata2;

    //regfile Regfile(.clk(clk), .reset(reset), .en(wb_write_to_regfile), .raddr1(inst[19:15]), .raddr2(inst[24:20]), .waddr(waddr), .wdata(wdata), .rdata1(rdata1), .rdata2(rdata2));


////////////////////////////////////////////////////////
    assign ALUControl = {
        inst_addi | inst_add  | inst_sb | inst_sh | inst_sw | inst_sd | inst_lb | inst_lh | inst_lbu | inst_lhu | inst_lw | inst_lwu | inst_ld,
        inst_addw | inst_addiw ,
        inst_sub,
        inst_subw,
        inst_lui,
        inst_auipc,
        inst_xor  | inst_xori,
        inst_or   | inst_ori,
        inst_and  | inst_andi,
        inst_sltu | inst_sltiu,
        inst_sll  | inst_slli,
        inst_sllw | inst_slliw,
        inst_srl  | inst_srli,
        inst_srlw | inst_srliw,
        inst_sra  | inst_srai,
        inst_sraw | inst_sraiw,
        inst_slt  | inst_slti
    };
////////////////////////////////////////////////////////
    wire is_branch = inst_beq  & (data1 == data2) |
                     inst_bne  & (data1 != data2) |
                     inst_blt  & (data1[63] == 0 ? (data2[63] == 1 ? 0 : data1 < data2) : (data2[63] == 0 ? 1 : data1 < data2)) |
                     inst_bge  & (data1[63] == 0 ? (data2[63] == 1 ? 1 : data1 >= data2) : (data2[63] == 0 ? 0 : data1 >= data2)) |
                     inst_bltu & (data1 <  data2) |
                     inst_bgeu & (data1 >= data2);
    assign is_jump = inst_jalr | inst_jal;

    wire [63:0] jump_pc;
    wire [63:0] branch_pc;
    wire [63:0] jalr_pc;
    
    assign jalr_pc = data1 + {{52{inst[31]}}, inst[31:20]};

    assign jump_pc = inst_jal ? inst_addr + {{(43){inst[31]}}, inst[31], inst[19:12], inst[20], inst[30:21], 1'b0} : {jalr_pc[63:1], 1'b0};
    assign branch_pc = inst_addr + {{(51){inst[31]}}, inst[31], inst[7], inst[30:25], inst[11:8], 1'b0};

    assign shift = inst_slli | inst_slliw | inst_srli | inst_srliw | inst_srai | inst_sraiw;
    assign shamt_ext = {58'd0, inst[25:20]};
    
    assign pcsource = is_jump | (is_branch & branch_op);
    assign b_j_pc = is_jump ? jump_pc : (is_branch & branch_op ? branch_pc : 64'd0);

    assign sext_imm = inst_auipc ? {{32{inst[31]}}, inst[31:12], 12'd0} : (inst_sb | inst_sh | inst_sw | inst_sd) ? {{52{imm_11_5_4_0[11]}}, imm_11_5_4_0[11:0]} : (inst_lui ? {{44{inst[31]}}, inst[31:12]} : {{53{imm_11_0[11]}}, imm_11_0[10:0]});
    assign aluimm = inst_lui | inst_auipc | inst_addi | inst_slti | inst_sltiu | inst_xori | inst_ori | inst_andi | inst_addiw | inst_lb | inst_lh | inst_lbu | inst_lhu | inst_lw | inst_lwu | inst_ld | inst_sb | inst_sh | inst_sw | inst_sd;

    assign mem_to_regfile = load_op;
    assign mem_control = inst_lb ? 4'b0001 : (inst_lh ? 4'b0010 : (inst_lbu ? 4'b0011 : (inst_lhu ? 4'b0100 : (inst_lw ? 4'b0101 : (inst_lwu ? 4'b0110 : (inst_ld ? 4'b0111 : (inst_sb ? 4'b1000 : (inst_sh ? 4'b1001 : (inst_sw ? 4'b1010 : (inst_sd ? 4'b1011 : 4'b0000))))))))));

    assign csr_wdata = (inst_csrrci | inst_csrrwi | inst_csrrsi) ? {59'd0, rs1} : rdata1;
    assign csr_control = {
        inst_csrrw | inst_csrrwi,
        inst_csrrs | inst_csrrsi,
        inst_csrrc | inst_csrrci
    };

    assign o_except_ena = i_except_ena ? 1'b1 : inst_ebreak | inst_ecall;
    assign o_excode = i_except_ena ? i_excode : (~inst_decode ? {1'b0, 63'd2} : (inst_ebreak ? {1'b0, 63'd3} : (inst_ecall ? {1'b0, 63'd11} : 64'd0)));

    assign flush_if_id = is_branch | is_jump;
    assign ret = inst_mret;
////////////////////////////////////////////////////////
    reg [1:0] fwda;
    reg [1:0] fwdb;

    always@(*) begin
        fwda = 2'b00;
        if(exe_write_to_regfile && (exe_out_addr != 0) && (rs1 == exe_out_addr) && ~exe_mem_to_regfile) begin
            fwda = 2'b01;
        end else begin
            if(mem_write_to_regfile && (mem_out_addr != 0) && (mem_out_addr == rs1) && ~mem_mem_to_regfile) begin
                fwda = 2'b10;
            end else begin
                if(mem_write_to_regfile && (mem_out_addr != 0) && (mem_out_addr == rs1) && mem_mem_to_regfile) begin
                    fwda = 2'b11;
                end
            end
        end
    end

    always@(*) begin
        fwdb = 2'b00;
        if(exe_write_to_regfile && (exe_out_addr != 0) && (rs2 == exe_out_addr) && ~exe_mem_to_regfile) begin
            fwdb = 2'b01;
        end else begin
            if(mem_write_to_regfile && (mem_out_addr != 0) && (mem_out_addr == rs2) && ~mem_mem_to_regfile) begin
                fwdb = 2'b10;
            end else begin
                if(mem_write_to_regfile && (mem_out_addr != 0) && (mem_out_addr == rs2) && mem_mem_to_regfile) begin
                    fwdb = 2'b11;
                end
            end
        end
    end

    mux4x64 mux1(.control(fwda), .a0(rdata1), .a1(exe_out), .a2(mem_out_1), .a3(mem_out_2), .out(data1));
    mux4x64 mux2(.control(fwdb), .a0(rdata2), .a1(exe_out), .a2(mem_out_1), .a3(mem_out_2), .out(data2));
////////////////////////////////////////////////////////
endmodule
module ysyx_210191_delay_stage(
    input clk,
    input reset,
    input [63:0] i_pc,
    input [31:0] i_inst,
    input i_write_to_regfile,
    input [4:0] i_reg_addr,
    input [63:0] i_data_out,
    input i_inst_r_valid,
    input [63:0] i_mstatus,
    input [63:0] i_mtvec,
    input [63:0] i_mepc,
    input [63:0] i_mcause,
    input [63:0] i_mie,
    input [63:0] i_mip,

    output reg [63:0] o_pc,
    output reg [31:0] o_inst,
    output reg o_write_to_regfile,
    output reg [4:0] o_reg_addr,
    output reg [63:0] o_data_out,
    output reg o_inst_r_valid,
    output reg [63:0] o_mstatus,
    output reg [63:0] o_mtvec,
    output reg [63:0] o_mepc,
    output reg [63:0] o_mcause,
    output reg [63:0] o_mie,
    output reg [63:0] o_mip
);
    always @(posedge clk) begin
        if(reset) begin
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_write_to_regfile <= 1'b0;
            o_reg_addr <= 5'b00000;
            o_data_out <= 64'd0;
            o_inst_r_valid <= 1'b0;
            o_mstatus <= 64'd0;
            o_mtvec <= 64'd0;
            o_mepc <= 64'd0;
            o_mcause <= 64'd0;
            o_mie <= 64'd0;
            o_mip <= 64'd0;
        end else begin
            o_pc <= i_pc;
            o_inst <= i_inst;
            o_write_to_regfile <= i_write_to_regfile;
            o_reg_addr <= i_reg_addr;
            o_data_out <= i_data_out;
            o_inst_r_valid <= i_inst_r_valid;
            o_mstatus <= i_mstatus;
            o_mtvec <= i_mtvec;
            o_mepc <= i_mepc;
            o_mcause <= i_mcause;
            o_mie <= i_mie;
            o_mip <= i_mip;
        end
    end
    
endmodulemodule exe(
    input [63:0] sext_imm,
    input aluimm,
    input [63:0] data1,
    input [63:0] data2,
    input is_jump,
    input [16:0] ALUControl,
    input [2:0] csr_control,
    input [63:0] csr_wdata,
    input [63:0] csr_data,
    input [63:0] i_pc,
    input shift,
    input [63:0] shamt_ext,

    output [63:0] data,
    output [63:0] csr_data_res,
    output write_ena

);

    wire [63:0] alu_data1;
    wire [63:0] alu_data2;
    wire [63:0] res;
    wire [63:0] csrrci;
    assign csrrci = csr_data & ~csr_wdata;

    assign alu_data1 = ALUControl == 17'b00000100000000000 ? i_pc : data1;
    assign alu_data2 =  aluimm ? sext_imm : (shift ? shamt_ext : data2);
    assign csr_data_res = csr_control == 3'b100 ? csr_wdata :
                        (csr_control == 3'b010 ? csr_data | csr_wdata :
                        (csr_control == 3'b001 ? {csr_data[63:5], csrrci[4:0]} : 64'd0));
    assign write_ena = csr_control[2] | csr_control[1] | csr_control[0];

    ALU alu(.data1(alu_data1), .data2(alu_data2), .ALUControl(ALUControl), .res(res));

    assign data = is_jump ? i_pc + 4 : ((csr_control[0] | csr_control[1] | csr_control[2]) ? csr_data : res);

endmodule
module ysyx_210191_exe_mem(
    input clk,
    input reset,
    input [5:0] stall,

    input i_write_to_mem,
    input i_write_to_regfile,
    input [4:0] i_reg_addr,
    input [63:0] i_data1,
    input [63:0] i_data2,
    input [3:0] i_mem_control,
    input i_mem_to_regfile,
    input [63:0] i_pc,
    input [31:0] i_inst,
    input [63:0] i_badvaddr,
    input [63:0] i_excode,
    input i_except_ena,
    input flush,
    input i_ret,
    input i_inst_r_valid,

    output reg o_write_to_mem,
    output reg o_write_to_regfile,
    output reg [4:0] o_reg_addr,
    output reg [63:0] o_data1,
    output reg [63:0] o_data2,
    output reg [3:0] o_mem_control,
    output reg o_mem_to_regfile,
    output reg [63:0] o_pc,
    output reg [31:0] o_inst,
    output reg [63:0] o_badvaddr,
    output reg [63:0] o_excode,
    output reg o_except_ena,
    output reg o_ret,
    output reg o_inst_r_valid
);

    always @(posedge clk) begin
        if(reset) begin
            o_write_to_mem <= 1'b0;
            o_write_to_regfile <= 1'b0;
            o_reg_addr <= 5'd0;
            o_data1 <= 64'd0;
            o_data2 <= 64'd0;
            o_mem_control <= 4'd0;
            o_mem_to_regfile <= 1'b0;
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_ret <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(flush) begin
            o_write_to_mem <= 1'b0;
            o_write_to_regfile <= 1'b0;
            o_reg_addr <= 5'd0;
            o_data1 <= 64'd0;
            o_data2 <= 64'd0;
            o_mem_control <= 4'd0;
            o_mem_to_regfile <= 1'b0;
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_ret <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(stall[3] == 1'b1 && stall[4] == 1'b0) begin
            o_write_to_mem <= 1'b0;
            o_write_to_regfile <= 1'b0;
            o_reg_addr <= 5'd0;
            o_data1 <= 64'd0;
            o_data2 <= 64'd0;
            o_mem_control <= 4'd0;
            o_mem_to_regfile <= 1'b0;
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_ret <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(stall[3] == 1'b0 && stall[4] == 1'b0) begin
            o_write_to_mem <= i_write_to_mem;
            o_write_to_regfile <= i_write_to_regfile;
            o_reg_addr <= i_reg_addr;
            o_data1 <= i_data1;
            o_data2 <= i_data2;
            o_mem_control <= i_mem_control;
            o_mem_to_regfile <= i_mem_to_regfile;
            o_pc <= i_pc;
            o_inst <= i_inst;
            o_badvaddr <= i_badvaddr;
            o_excode <= i_excode;
            o_except_ena <= i_except_ena;
            o_ret <= i_ret;
            o_inst_r_valid <= i_inst_r_valid;
        end
    end

endmodule
module ysyx_210191_id_exe(
    input clk,
    input reset,
    input [5:0] stall,

    input i_write_to_mem,
    input i_write_to_regfile,
    input [4:0] i_reg_addr,
    input [16:0] i_ALUControl,
    input [63:0] i_sext_imm,
    input i_aluimm,
    input [63:0] i_data1,
    input [63:0] i_data2,
    input i_is_jump,
    input [3:0] i_mem_control,
    input i_mem_to_regfile,
    input [63:0] i_pc,
    input [31:0] i_inst,
    input [11:0] i_csr,
    input [63:0] i_csr_wdata,
    input [2:0] i_csr_control,
    input [63:0] i_badvaddr,
    input [63:0] i_excode,
    input i_except_ena,
    input flush,
    input i_ret,
    input i_inst_r_valid,
    input i_shift,
    input [63:0] i_shamt_ext,

    output reg o_write_to_mem,
    output reg o_write_to_regfile,
    output reg [4:0] o_reg_addr, //回到control_unit
    output reg [16:0] o_ALUControl,
    output reg [63:0] o_sext_imm,
    output reg o_aluimm,
    output reg [63:0] o_data1,
    output reg [63:0] o_data2,
    output reg o_is_jump,
    output reg [3:0] o_mem_control,
    output reg o_mem_to_regfile,
    output reg [63:0] o_pc,
    output reg [31:0] o_inst,
    output reg [11:0] o_csr,
    output reg [63:0] o_csr_wdata,
    output reg [2:0] o_csr_control,
    output reg [63:0] o_badvaddr,
    output reg [63:0] o_excode,
    output reg o_except_ena,
    output reg o_ret,
    output reg o_inst_r_valid,
    output reg o_shift,
    output reg [63:0] o_shamt_ext
);

    always@(posedge clk) begin
        if(reset) begin
            o_write_to_mem <= 1'b0;
            o_write_to_regfile <= 1'b0;
            o_reg_addr <= 5'd0;
            o_ALUControl <= 17'd0;
            o_sext_imm <= 64'd0;
            o_aluimm <= 1'b0;
            o_data1 <= 64'd0;
            o_data2 <= 64'd0;
            o_is_jump <= 1'b0;
            o_mem_control <= 4'b0000;
            o_mem_to_regfile <= 1'b0;
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_csr <= 12'd0;
            o_csr_wdata <= 63'd0;
            o_csr_control <= 3'b000;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_ret <= 1'b0;
            o_inst_r_valid <= 1'b0;
            o_shift <= 1'b0;
            o_shamt_ext <= 64'd0;
        end else if(flush) begin
            o_write_to_mem <= 1'b0;
            o_write_to_regfile <= 1'b0;
            o_reg_addr <= 5'd0;
            o_ALUControl <= 17'd0;
            o_sext_imm <= 64'd0;
            o_aluimm <= 1'b0;
            o_data1 <= 64'd0;
            o_data2 <= 64'd0;
            o_is_jump <= 1'b0;
            o_mem_control <= 4'b0000;
            o_mem_to_regfile <= 1'b0;
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_csr <= 12'd0;
            o_csr_wdata <= 63'd0;
            o_csr_control <= 3'b000;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_ret <= 1'b0;
            o_inst_r_valid <= 1'b0;
            o_shift <= 1'b0;
            o_shamt_ext <= 64'd0;
        end else if(stall[2] == 1'b1 && stall[3] == 1'b0) begin
            o_write_to_mem <= 1'b0;
            o_write_to_regfile <= 1'b0;
            o_reg_addr <= 5'd0;
            o_ALUControl <= 17'd0;
            o_sext_imm <= 64'd0;
            o_aluimm <= 1'b0;
            o_data1 <= 64'd0;
            o_data2 <= 64'd0;
            o_is_jump <= 1'b0;
            o_mem_control <= 4'b0000;
            o_mem_to_regfile <= 1'b0;
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_csr <= 12'd0;
            o_csr_wdata <= 63'd0;
            o_csr_control <= 3'b000;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_ret <= 1'b0;
            o_inst_r_valid <= 1'b0;
            o_shift <= 1'b0;
            o_shamt_ext <= 64'd0;
        end else if(stall[2] == 1'b0 && stall[3] == 1'b0) begin
            o_write_to_mem <= i_write_to_mem;
            o_write_to_regfile <= i_write_to_regfile;
            o_reg_addr <= i_reg_addr;
            o_ALUControl <= i_ALUControl;
            o_sext_imm <= i_sext_imm;
            o_aluimm <= i_aluimm;
            o_data1 <= i_data1;
            o_data2 <= i_data2;
            o_is_jump <= i_is_jump;
            o_mem_control <= i_mem_control;
            o_mem_to_regfile <= i_mem_to_regfile;
            o_pc <= i_pc;
            o_inst <= i_inst;
            o_csr <= i_csr;
            o_csr_wdata <= i_csr_wdata;
            o_csr_control <= i_csr_control;
            o_badvaddr <= i_badvaddr;
            o_excode <= i_excode;
            o_except_ena <= i_except_ena;
            o_ret <= i_ret;
            o_inst_r_valid <= i_inst_r_valid;
            o_shift <= i_shift;
            o_shamt_ext <= i_shamt_ext;
        end
    end

endmodule
module ysyx_210191_If(
    input clk,
    input reset,
    input inst_r_valid,
    input stall_from_mem,
    input flush_if_id,

    output stall_o,
    output reg inst_r_ena
);
    assign stall_o = ~inst_r_valid;
    
    always @(posedge clk) begin
        if(reset) begin
            inst_r_ena <= 1'b0;
        end else begin
            if(stall_from_mem) begin
                inst_r_ena <= 1'b0;
            end else begin
                inst_r_ena <= 1'b1;
            end
        end
    end

endmodule
module ysyx_210191_if_id(
    input clk,
    input reset,
    input [5:0] stall,

    input [31:0] i_inst,
    input [63:0] i_inst_addr,
    input [63:0] i_pc,
    input [63:0] i_badvaddr,
    input [63:0] i_excode,
    input i_except_ena,
    input i_inst_r_valid,
    input flush_if_id,
    input flush,
    input keep,

    output reg [31:0] o_inst,
    output reg [63:0] o_inst_addr,
    output reg [63:0] o_pc,
    output reg [63:0] o_badvaddr,
    output reg [63:0] o_excode,
    output reg o_except_ena,
    output reg o_inst_r_valid
);

    always @(posedge clk) begin
        if(reset) begin
            o_inst <= 32'd0;
            o_inst_addr <= 64'h0000000080000000;
            o_pc <= 64'h0000000080000000;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(flush) begin
            o_inst <= 32'd0;
            o_inst_addr <= 64'h0000000080000000;
            o_pc <= 64'h0000000080000000;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(keep) begin
            o_inst <= 32'd0;
            o_inst_addr <= 64'h0000000080000000;
            o_pc <= 64'h0000000080000000;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(stall[1] == 1'b1 && stall[2] == 1'b0) begin
            o_inst <= 32'd0;
            o_inst_addr <= 64'h0000000080000000;
            o_pc <= 64'h0000000080000000;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(stall[1] == 1'b0 && stall[2] == 1'b0) begin
            if(flush_if_id) begin
                o_inst <= 32'd0;
                o_inst_addr <= 64'h0000000080000000;
                o_pc <= 64'h0000000080000000;
                o_badvaddr <= 64'd0;
                o_excode <= 64'd0;
                o_except_ena <= 1'b0;
                o_inst_r_valid <= 1'b0;
            end else begin
                o_inst <= i_inst;
                o_inst_addr <= i_inst_addr;
                o_pc <= i_pc;
                o_badvaddr <= i_badvaddr;
                o_excode <= i_excode;
                o_except_ena <= i_except_ena;
                o_inst_r_valid <= i_inst_r_valid;
            end
        end
    end
endmodule
module ysyx_210191_mem(
    input [63:0] mem_data_i,
    input [3:0] mem_control,
    input [63:0] mem_addr,
    input [63:0] i_badvaddr,
    input [63:0] i_excode,
    input i_except_ena,
    input data_w_valid,
    input data_r_valid,
    input [63:0] mem_wdata,

    output reg [63:0] mem_data_o,
    output reg [7:0] mem_mask,
    output data_r_ena,
    output data_w_ena,
    output [63:0] data_w_addr,
    output [63:0] o_badvaddr,
    output [63:0] o_excode,
    output o_except_ena,
    output stall_o,
    output [63:0] data_w_data,
    output [63:0] data_r_addr,

    output mtime_ena,
    output mtimecmp_ena,
    output [63:0] time_wdata,
    input [63:0] mtime_data,
    input [63:0] mtimecmp_data
);

    always @(mem_control) begin
        case (mem_control)
            4'b0001 : begin
                case(mem_addr[2:0])
                    3'b000 : begin
                        mem_data_o = {{56{mem_r_data[7]}}, mem_r_data[7:0]};
                    end
                    3'b001 : begin
                        mem_data_o = {{56{mem_r_data[15]}}, mem_r_data[15:8]};
                    end
                    3'b010 : begin
                        mem_data_o = {{56{mem_r_data[23]}}, mem_r_data[23:16]};
                    end
                    3'b011 : begin
                        mem_data_o = {{56{mem_r_data[31]}}, mem_r_data[31:24]};
                    end
                    3'b100 : begin
                        mem_data_o = {{56{mem_r_data[39]}}, mem_r_data[39:32]};
                    end
                    3'b101 : begin
                        mem_data_o = {{56{mem_r_data[47]}}, mem_r_data[47:40]};
                    end
                    3'b110 : begin
                        mem_data_o = {{56{mem_r_data[55]}}, mem_r_data[55:48]};
                    end
                    3'b111 : begin
                        mem_data_o = {{56{mem_r_data[63]}}, mem_r_data[63:56]};
                    end
                    default : begin
                        mem_data_o = 64'd0;
                    end
                endcase
            end
            4'b0010 : begin
                case(mem_addr[2:0])
                    3'b000 : begin
                        mem_data_o = {{48{mem_r_data[15]}}, mem_r_data[15:0]};
                    end
                    3'b010 : begin
                        mem_data_o = {{48{mem_r_data[31]}}, mem_r_data[31:16]};
                    end
                    3'b100 : begin
                        mem_data_o = {{48{mem_r_data[47]}}, mem_r_data[47:32]};
                    end
                    3'b110 : begin
                        mem_data_o = {{48{mem_r_data[63]}}, mem_r_data[63:48]};
                    end
                    default : begin
                        mem_data_o = 64'd0;
                    end
                endcase
            end
            4'b0011 : begin
                case(mem_addr[2:0])
                    3'b000 : begin
                        mem_data_o = {56'd0, mem_r_data[7:0]};
                    end
                    3'b001 : begin
                        mem_data_o = {56'd0, mem_r_data[15:8]};
                    end
                    3'b010 : begin
                        mem_data_o = {56'd0, mem_r_data[23:16]};
                    end
                    3'b011 : begin
                        mem_data_o = {56'd0, mem_r_data[31:24]};
                    end
                    3'b100 : begin
                        mem_data_o = {56'd0, mem_r_data[39:32]};
                    end
                    3'b101 : begin
                        mem_data_o = {56'd0, mem_r_data[47:40]};
                    end
                    3'b110 : begin
                        mem_data_o = {56'd0, mem_r_data[55:48]};
                    end
                    3'b111 : begin
                        mem_data_o = {56'd0, mem_r_data[63:56]};
                    end
                    default : begin
                        mem_data_o = 64'd0;
                    end
                endcase
            end
            4'b0100 : begin
                case(mem_addr[2:0])
                    3'b000 : begin
                        mem_data_o = {48'd0, mem_r_data[15:0]};
                    end
                    3'b010 : begin
                        mem_data_o = {48'd0, mem_r_data[31:16]};
                    end
                    3'b100 : begin
                        mem_data_o = {48'd0, mem_r_data[47:32]};
                    end
                    3'b110 : begin
                        mem_data_o = {48'd0, mem_r_data[63:48]};
                    end
                    default : begin
                        mem_mask = 8'b00000000;
                    end
                endcase
            end
            4'b0101 : begin
                case(mem_addr[2:0])
                    3'b000 : begin
                        mem_data_o = {{32{mem_r_data[31]}}, mem_r_data[31:0]};
                    end
                    3'b100 : begin
                        mem_data_o = {{32{mem_r_data[63]}}, mem_r_data[63:32]};
                    end
                    default : begin
                        mem_data_o = 64'd0;
                    end
                endcase
            end
            4'b0110 : begin
                case(mem_addr[2:0])
                    3'b000 : begin
                        mem_data_o = {32'd0, mem_r_data[31:0]};
                    end
                    3'b100 : begin
                        mem_data_o = {32'd0, mem_r_data[63:32]};
                    end
                    default : begin
                        mem_data_o = 64'd0;
                    end
                endcase
            end
            4'b0111 : begin
                mem_data_o = mem_r_data;
            end
            4'b1000 : begin
                case(mem_addr[2:0])
                    3'b000 : begin
                        mem_mask = 8'b00000001;
                        //data_w_data = {mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0]};
                    end
                    3'b001 : begin
                        mem_mask = 8'b00000010;
                        //data_w_data = {mem_wdata[15:8], mem_wdata[15:8], mem_wdata[15:8], mem_wdata[15:8], mem_wdata[15:8], mem_wdata[15:8], mem_wdata[15:8], mem_wdata[15:8]};
                    end
                    3'b010 : begin
                        mem_mask = 8'b00000100;
                        //data_w_data = {mem_wdata[23:16], mem_wdata[23:16], mem_wdata[23:16], mem_wdata[23:16], mem_wdata[23:16], mem_wdata[23:16], mem_wdata[23:16], mem_wdata[23:16]};
                    end
                    3'b011 : begin
                        mem_mask = 8'b00001000;
                        //data_w_data = {mem_wdata[31:24], mem_wdata[31:24], mem_wdata[31:24], mem_wdata[31:24], mem_wdata[31:24], mem_wdata[31:24], mem_wdata[31:24], mem_wdata[31:24]};
                    end
                    3'b100 : begin
                        mem_mask = 8'b00010000;
                        //data_w_data = {mem_wdata[39:32], mem_wdata[39:32], mem_wdata[39:32], mem_wdata[39:32], mem_wdata[39:32], mem_wdata[39:32], mem_wdata[39:32], mem_wdata[39:32]};
                    end
                    3'b101 : begin
                        mem_mask = 8'b00100000;
                        //data_w_data = {mem_wdata[47:40], mem_wdata[47:40], mem_wdata[47:40], mem_wdata[47:40], mem_wdata[47:40], mem_wdata[47:40], mem_wdata[47:40], mem_wdata[47:40]};
                    end
                    3'b110 : begin
                        mem_mask = 8'b01000000;
                        //data_w_data = {mem_wdata[55:48], mem_wdata[55:48], mem_wdata[55:48], mem_wdata[55:48], mem_wdata[55:48], mem_wdata[55:48], mem_wdata[55:48], mem_wdata[55:48]};
                    end
                    3'b111 : begin
                        mem_mask = 8'b10000000;
                        //data_w_data = {mem_wdata[63:56], mem_wdata[63:56], mem_wdata[63:56], mem_wdata[63:56], mem_wdata[63:56], mem_wdata[63:56], mem_wdata[63:56], mem_wdata[63:56]};
                    end
                    default : begin
                        mem_mask = 8'b00000000;
                    end
                endcase
            end
            4'b1001 : begin
                case(mem_addr[2:0])
                    3'b000 : begin
                        mem_mask = 8'b00000011;
                        //data_w_data = {mem_wdata[15:0], mem_wdata[15:0], mem_wdata[15:0], mem_wdata[15:0]};
                    end
                    3'b010 : begin
                        mem_mask = 8'b00001100;
                        //data_w_data = {mem_wdata[31:16], mem_wdata[31:16], mem_wdata[31:16], mem_wdata[31:16]};
                    end
                    3'b100 : begin
                        mem_mask = 8'b00110000;
                        //data_w_data = {mem_wdata[47:32], mem_wdata[47:32], mem_wdata[47:32], mem_wdata[47:32]};
                    end
                    3'b110 : begin
                        mem_mask = 8'b11000000;
                        //data_w_data = {mem_wdata[63:48], mem_wdata[63:48], mem_wdata[63:48], mem_wdata[63:48]};
                    end
                    default : begin
                        mem_mask = 8'b00000000;
                    end
                endcase
            end
            4'b1010 : begin
                case(mem_addr[2:0])
                    3'b000 : begin
                        mem_mask = 8'b00001111;
                        //data_w_data = {mem_wdata[31:0], mem_wdata[31:0]};
                    end
                    3'b100 : begin
                        mem_mask = 8'b11110000;
                        //data_w_data = {mem_wdata[63:32], mem_wdata[63:32]};
                    end
                    default : begin
                        mem_mask = 8'b00000000;
                    end
                endcase
            end
            4'b1011 : begin
                mem_mask = 8'b11111111;
                //data_w_data = mem_wdata[63:0];
            end
            default : begin
                mem_mask = 8'b00000000;
                mem_data_o = 64'd0;
            end
        endcase
    end    

    assign data_w_addr = mem_addr;
    assign data_r_addr = mem_addr;
    assign data_w_data = mem_control == 4'b1000 ? {mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0], mem_wdata[7:0]} : (mem_control == 4'b1001 ? {mem_wdata[15:0], mem_wdata[15:0], mem_wdata[15:0], mem_wdata[15:0]} : (mem_control == 4'b1010 ? {mem_wdata[31:0], mem_wdata[31:0]} : (mem_control == 4'b1011 ? mem_wdata : 64'd0)));
    assign stall_o = ((~data_r_valid && (mem_control == 4'b0001 | mem_control == 4'b0010 | mem_control == 4'b0011 | mem_control == 4'b0100 | mem_control == 4'b0101 | mem_control == 4'b0110 | mem_control == 4'b0111)) || (~data_w_valid && (mem_control == 4'b1000 | mem_control == 4'b1001 | mem_control == 4'b1010 | mem_control == 4'b1011))) && mem_addr != 64'h0000000002004000 && mem_addr != 64'h000000000200bff8;
    assign data_r_ena = ~data_r_valid && (mem_control == 4'b0001 | mem_control == 4'b0010 | mem_control == 4'b0011 | mem_control == 4'b0100 | mem_control == 4'b0101 | mem_control == 4'b0110 | mem_control == 4'b0111) && mem_addr != 64'h0000000002004000 && mem_addr != 64'h000000000200bff8;
    assign data_w_ena = ~data_w_valid && (mem_control == 4'b1000 | mem_control == 4'b1001 | mem_control == 4'b1010 | mem_control == 4'b1011) && mem_addr != 64'h0000000002004000 && mem_addr != 64'h000000000200bff8;
    //assign control = (mem_control == 4'b0000 | mem_control == 4'b0001 | mem_control == 4'b0010 | mem_control == 4'b0011 | mem_control == 4'b0100 | mem_control == 4'b0101 | mem_control == 4'b0110) ? 2'b01 : (mem_control == 4'b0111 | mem_control == 4'b1000 | mem_control == 4'b1001 | mem_control == 4'b1010 ? 2'b10 : 2'b00); 
    assign o_except_ena = i_except_ena == 1'b1 ? 1'b1 : (((mem_control == 4'b0100 || mem_control == 4'b0101) && mem_addr[0] != 1'b0) || (mem_control == 4'b0110 && mem_addr[1:0] != 2'b00) || (mem_control == 4'b0111 && mem_addr[2:0] != 3'b000) || (mem_control == 4'b1001 && mem_addr[0] != 1'b0) || (mem_control == 4'b1010 && mem_addr[1:0] != 2'b00) || (mem_control == 4'b1011 && mem_addr[2:0] != 3'b000));
    assign o_excode = i_except_ena ? i_excode : (((mem_control == 4'b0100 || mem_control == 4'b0101) && mem_addr[0] != 1'b0) || (mem_control == 4'b0110 && mem_addr[1:0] != 2'b00) || (mem_control == 4'b0111 && mem_addr[2:0] != 3'b000) ? {1'b0, 63'd4} : ((mem_control == 4'b1001 && mem_addr[0] != 1'b0) || (mem_control == 4'b1010 && mem_addr[1:0] != 2'b00) || (mem_control == 4'b1011 && mem_addr[2:0] != 3'b000) ? {1'b0, 63'd6} : 64'd0));
    assign mtime_ena = (mem_control == 4'b1000 | mem_control == 4'b1001 | mem_control == 4'b1010 | mem_control == 4'b1011) && mem_addr == 64'h000000000200bff8;
    assign mtime_ena = (mem_control == 4'b1000 | mem_control == 4'b1001 | mem_control == 4'b1010 | mem_control == 4'b1011) && mem_addr == 64'h0000000002004000;
    assign time_wdata = data_w_data;

    wire [63:0] mem_r_data;
    assign mem_r_data = mem_addr == 64'h0000000002004000 ? mtimecmp_data : (mem_addr == 64'h000000000200bff8 ? mtime_data : mem_data_i);
endmodule
module ysyx_210191_mem_wb(
    input clk,
    input reset,
    input [5:0] stall,

    input i_write_to_regfile,//回id
    input i_mem_to_regfile,
    input [4:0] i_reg_addr,//回id
    input [63:0] i_alu_data,
    input [63:0] i_mem_data,
    input [63:0] i_pc,
    input [31:0] i_inst,
    input [63:0] i_badvaddr,
    input [63:0] i_excode,
    input i_except_ena,
    input flush,
    input i_ret,
    input i_inst_r_valid,
    input i_mtime_int,

    output reg o_write_to_regfile,
    output reg o_mem_to_regfile,
    output reg [4:0] o_reg_addr,
    output reg [63:0] o_alu_data,
    output reg [63:0] o_mem_data,
    output reg [63:0] o_pc,
    output reg [31:0] o_inst,
    output reg [63:0] o_badvaddr,
    output reg [63:0] o_excode,
    output reg o_except_ena,
    output reg o_ret,
    output reg o_inst_r_valid,
    output reg o_mtime_int
);

    always @(posedge clk) begin
        if(reset) begin
            o_write_to_regfile <= 1'b0;
            o_mem_to_regfile <= 1'b0;
            o_reg_addr <= 5'd0;
            o_alu_data <= 64'd0;
            o_mem_data <= 64'd0;
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_ret <= 1'b0;
            o_inst_r_valid <= 1'b0;
            o_mtime_int <= 1'b0;
        end else if(flush) begin
            o_write_to_regfile <= 1'b0;
            o_mem_to_regfile <= 1'b0;
            o_reg_addr <= 5'd0;
            o_alu_data <= 64'd0;
            o_mem_data <= 64'd0;
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_ret <= 1'b0;
            o_inst_r_valid <= 1'b0;
            o_mtime_int <= 1'b0;
        end else if(stall[4] == 1'b1 && stall[5] == 1'b0) begin
            o_write_to_regfile <= 1'b0;
            o_mem_to_regfile <= 1'b0;
            o_reg_addr <= 5'd0;
            o_alu_data <= 64'd0;
            o_mem_data <= 64'd0;
            o_pc <= 64'h0000000080000000;
            o_inst <= 32'd0;
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_ret <= 1'b0;
            o_inst_r_valid <= 1'b0;
            o_mtime_int <= 1'b0;
        end else if(stall[4] == 1'b0 && stall[5] == 1'b0) begin
            o_write_to_regfile <= i_write_to_regfile;
            o_mem_to_regfile <= i_mem_to_regfile;
            o_reg_addr <= i_reg_addr;
            o_alu_data <= i_alu_data;
            o_mem_data <= i_mem_data;
            o_pc <= i_pc;
            o_inst <= i_inst;
            o_badvaddr <= i_badvaddr;
            o_excode <= i_excode;
            o_except_ena <= i_except_ena;
            o_ret <= i_ret;
            o_inst_r_valid <= i_inst_r_valid;
            o_mtime_int <= i_mtime_int;
        end
    end
endmodule
module ysyx_210191_mux4x64(
    input  [1:0] control,
    input  [63:0] a0,
    input  [63:0] a1,
    input  [63:0] a2,
    input  [63:0] a3,
    output [63:0] out
);
    assign out = control == 2'b00 ? a0 : (control == 2'b01 ? a1 : (control == 2'b10 ? a2 : a3));
endmodule
module ysyx_210191_mycpu(
    input clock,
    input reset,

    input data_r_valid,
    input data_w_valid,
    input [63:0] data_r_data,
    input [31:0] inst_r_data,
    input inst_r_valid,

    output inst_r_ena,
    output [63:0] inst_r_addr,
    output [63:0] data_w_addr,
    output [63:0] data_w_data,
    output data_w_ena,
    output data_r_ena,
    output [63:0] data_r_addr,
    output [7:0] mem_mask,
    output flush
    
);
    wire [5:0] stall;
    wire [63:0] npc;
    wire [63:0] pc;
    wire [31:0] if_id_o_inst;
    wire [63:0] if_id_o_inst_addr;
    wire [63:0] if_id_pc;
    wire [63:0] if_id_badvaddr;
    wire [63:0] if_id_excode;
    wire if_id_except_ena;
    wire id_write_to_mem;
    wire id_write_to_regfile;
    wire [4:0] id_reg_addr;
    wire [16:0] id_ALUControl;
    wire id_pcsource;
    wire [63:0] b_j_pc;
    wire [63:0] id_sext_imm;
    wire id_aluimm;
    wire [63:0] id_data1;
    wire [63:0] id_data2;
    wire id_is_jump;
    wire [3:0] id_mem_control;
    wire id_mem_to_regfile;
    wire [11:0] id_csr;
    wire [63:0] id_csr_wdata;
    wire [2:0] id_csr_control;
    wire [63:0] id_badvaddr;
    wire [63:0] id_excode;
    wire id_except_ena;
    wire [63:0] id_o_excode;
    wire id_o_except_ena;
    wire id_o_ret;
    wire id_o_shift;
    wire [63:0] id_o_shamt_ext;
    wire id_inst_r_valid;
    wire exe_write_to_mem;
    wire exe_write_to_regfile;
    wire [4:0] exe_reg_addr;
    wire [16:0] exe_ALUControl;
    wire [63:0] exe_sext_imm;
    wire exe_aluimm;
    wire [63:0] exe_data1;
    wire [63:0] exe_data2;
    wire [63:0] exe_jump_pc;
    wire exe_is_jump;
    wire [3:0] exe_mem_control;
    wire exe_mem_to_regfile;
    wire [63:0] exe_data;
    wire [63:0] exe_pc;
    wire [31:0] exe_inst;
    wire [11:0] exe_csr;
    wire [63:0] exe_csr_wdata;
    wire [2:0] exe_csr_control;
    wire [63:0] exe_badvaddr;
    wire [63:0] exe_excode;
    wire exe_except_ena;
    wire exe_ret;
    wire [63:0] exe_o_csr_data_res;
    wire exe_o_write_ena;
    wire exe_inst_r_valid;
    wire exe_shift;
    wire [63:0] exe_shamt_ext;
    wire mem_write_to_mem;
    wire mem_write_to_regfile;
    wire [4:0] mem_reg_addr;
    wire [63:0] mem_data1;
    wire [63:0] mem_data2;
    wire [3:0] mem_mem_control;
    wire mem_mem_to_regfile;
    wire [63:0] mem_data_o;
    wire [63:0] mem_pc;
    wire [31:0] mem_inst;
    wire [63:0] mem_badvaddr;
    wire [63:0] mem_excode;
    wire mem_except_ena;
    wire mem_wb_except_ena;
    wire [63:0] mem_o_badvaddr;
    wire [63:0] mem_o_excode;
    wire mem_ret;
    wire mem_inst_r_valid;
    wire [63:0] wb_write_to_regfile;
    wire wb_mem_to_regfile;
    wire [4:0] wb_reg_addr;
    wire [63:0] wb_alu_data;
    wire [63:0] wb_mem_data;
    wire [63:0] wb_data_out;
    wire [63:0] wb_pc;
    wire [31:0] wb_inst;
    wire [63:0] wb_badvaddr;
    wire [63:0] wb_excode;
    wire wb_except_ena;
    wire wb_ret;
    wire wb_inst_r_valid;
    wire [63:0] rdata1;
    wire [63:0] rdata2;
    wire [63:0] csr_data;
    wire [63:0] csr_wdata;
    wire csr_write_ena;

    wire flush_if_id;
    wire [63:0] new_pc;
    wire ret;
    wire [63:0] mtvec_pc;
    wire [63:0] epc;
    wire stall_from_if;
    wire stall_from_mem;
    wire [63:0] time_wdata;
    wire mtimecmp_ena;
    wire mtime_ena;
    wire mem_mtime_int;
    wire [63:0] mtime_data;
    wire [63:0] mtimecmp_data;
    wire csr_mtime_int;
    wire keep;

    wire [7:0] wdest;
    assign wdest = {3'b000, {wb_reg_addr[4:0]}};
    wire [63:0] regs[0:31];
    wire [63:0] delay_pc;
    wire [31:0] delay_inst;
    wire delay_write_to_regfile;
    wire [4:0] delay_reg_addr;
    wire [63:0] delay_data_out;
    wire delay_inst_r_valid;

    wire [63:0] csr_mstatus;
    wire [63:0] csr_mtvec;
    wire [63:0] csr_mepc;
    wire [63:0] csr_mcause;
    wire [63:0] csr_mie;
    wire [63:0] csr_mip;
    wire [63:0] csr_mscratch;
    wire [63:0] csr_sstatus;
    wire [63:0] delay_mstatus;
    wire [63:0] delay_mtvec;
    wire [63:0] delay_mepc;
    wire [63:0] delay_mcause;
    wire [63:0] delay_mie;
    wire [63:0] delay_mip;

/////////////////////////////////////////////
// Difftest
reg cmt_wen;
reg [7:0] cmt_wdest;
reg [63:0] cmt_wdata;
reg [63:0] cmt_pc;
reg [31:0] cmt_inst;
reg cmt_valid;
reg trap;
reg [7:0] trap_code;
reg [63:0] cycleCnt;
reg [63:0] instrCnt;
reg [63:0] regs_diff [0 : 31];
reg [63:0] mstatus;
reg [63:0] mtvec;
reg [63:0] mepc;
reg [63:0] mcause;
reg [63:0] mie;
reg [63:0] mip;
reg [63:0] mscratch;
reg [63:0] sstatus;
reg skip;

wire inst_valid = delay_inst_r_valid;
wire [63:0] a0;

always @(posedge clock) begin
  if (reset) begin
    {cmt_wen, cmt_wdest, cmt_wdata, cmt_pc, cmt_inst, cmt_valid, trap, trap_code, cycleCnt, instrCnt, skip} <= 0;
  end
  else if (~trap) begin
    cmt_wen <= delay_write_to_regfile;
    cmt_wdest <= {3'd0, delay_reg_addr};
    cmt_wdata <= delay_data_out;
    cmt_pc <= {delay_pc[63:32], 1'b1, delay_pc[30:0]};
    cmt_inst <= delay_inst;
    cmt_valid <= inst_valid;

    mstatus <= csr_mstatus;
    mtvec <= csr_mtvec;
    mepc <= csr_mepc;
    mcause <= csr_mcause;
    mie <= csr_mie;
    mip <= csr_mip;
    mscratch <= csr_mscratch;
    sstatus <= csr_sstatus;

		regs_diff <= regs;

    trap <= delay_inst[6:0] == 7'h6b;
    trap_code <= regs[10][7:0];
    cycleCnt <= cycleCnt + 1;
    instrCnt <= instrCnt + inst_valid;
    skip <= delay_inst == 32'h0000007b || delay_inst == 32'hff86b683 || delay_inst == 32'h00d7b023 ? 1'b1 : 1'b0;
    if(delay_inst == 32'h0000007b) begin
      $write("%c", a0);
    end
  end
end

DifftestInstrCommit DifftestInstrCommit(
  .clock              (clock),
  .coreid             (0),
  .index              (0),
  .valid              (cmt_valid),
  .pc                 (cmt_pc),
  .instr              (cmt_inst),
  .skip               (skip),
  .isRVC              (0),
  .scFailed           (0),
  .wen                (cmt_wen),
  .wdest              (cmt_wdest),
  .wdata              (cmt_wdata)
);

DifftestArchIntRegState DifftestArchIntRegState (
  .clock              (clock),
  .coreid             (0),
  .gpr_0              (regs_diff[0]),
  .gpr_1              (regs_diff[1]),
  .gpr_2              (regs_diff[2]),
  .gpr_3              (regs_diff[3]),
  .gpr_4              (regs_diff[4]),
  .gpr_5              (regs_diff[5]),
  .gpr_6              (regs_diff[6]),
  .gpr_7              (regs_diff[7]),
  .gpr_8              (regs_diff[8]),
  .gpr_9              (regs_diff[9]),
  .gpr_10             (regs_diff[10]),
  .gpr_11             (regs_diff[11]),
  .gpr_12             (regs_diff[12]),
  .gpr_13             (regs_diff[13]),
  .gpr_14             (regs_diff[14]),
  .gpr_15             (regs_diff[15]),
  .gpr_16             (regs_diff[16]),
  .gpr_17             (regs_diff[17]),
  .gpr_18             (regs_diff[18]),
  .gpr_19             (regs_diff[19]),
  .gpr_20             (regs_diff[20]),
  .gpr_21             (regs_diff[21]),
  .gpr_22             (regs_diff[22]),
  .gpr_23             (regs_diff[23]),
  .gpr_24             (regs_diff[24]),
  .gpr_25             (regs_diff[25]),
  .gpr_26             (regs_diff[26]),
  .gpr_27             (regs_diff[27]),
  .gpr_28             (regs_diff[28]),
  .gpr_29             (regs_diff[29]),
  .gpr_30             (regs_diff[30]),
  .gpr_31             (regs_diff[31])
);

DifftestTrapEvent DifftestTrapEvent(
  .clock              (clock),
  .coreid             (0),
  .valid              (trap),
  .code               (trap_code),
  .pc                 (cmt_pc),
  .cycleCnt           (cycleCnt),
  .instrCnt           (instrCnt)
);

DifftestCSRState DifftestCSRState(
  .clock              (clock),
  .coreid             (0),
  .priviledgeMode     (3),
  .mstatus            (mstatus),
  .sstatus            (sstatus),
  .mepc               (mepc),
  .sepc               (0),
  .mtval              (0),
  .stval              (0),
  .mtvec              (mtvec),
  .stvec              (0),
  .mcause             (mcause),
  .scause             (0),
  .satp               (0),
  .mip                (mip),
  .mie                (mie),
  .mscratch           (mscratch),
  .sscratch           (0),
  .mideleg            (0),
  .medeleg            (0)
);

DifftestArchFpRegState DifftestArchFpRegState(
  .clock              (clock),
  .coreid             (0),
  .fpr_0              (0),
  .fpr_1              (0),
  .fpr_2              (0),
  .fpr_3              (0),
  .fpr_4              (0),
  .fpr_5              (0),
  .fpr_6              (0),
  .fpr_7              (0),
  .fpr_8              (0),
  .fpr_9              (0),
  .fpr_10             (0),
  .fpr_11             (0),
  .fpr_12             (0),
  .fpr_13             (0),
  .fpr_14             (0),
  .fpr_15             (0),
  .fpr_16             (0),
  .fpr_17             (0),
  .fpr_18             (0),
  .fpr_19             (0),
  .fpr_20             (0),
  .fpr_21             (0),
  .fpr_22             (0),
  .fpr_23             (0),
  .fpr_24             (0),
  .fpr_25             (0),
  .fpr_26             (0),
  .fpr_27             (0),
  .fpr_28             (0),
  .fpr_29             (0),
  .fpr_30             (0),
  .fpr_31             (0)
);

/////////////////////////////////////////////

    pc PC(.clk(clock), .reset(reset), .stall(stall), .b_j_pc(b_j_pc), .pcsource(id_pcsource), .new_pc(new_pc), .flush(flush), .ret(wb_ret), .flush_if_id(flush_if_id), .o_inst_addr(inst_r_addr), .o_badvaddr(if_id_badvaddr), .o_excode(if_id_excode), .o_except_ena(if_id_except_ena), .keep(keep));

    If IF(.clk(clock), .reset(reset), .inst_r_valid(inst_r_valid), .stall_from_mem(stall_from_mem), .flush_if_id(flush_if_id), .stall_o(stall_from_if), .inst_r_ena(inst_r_ena));

    regfile Regfile(.clk(clock), .reset(reset), .en(wb_write_to_regfile), .raddr1(if_id_o_inst[19:15]), .raddr2(if_id_o_inst[24:20]), .waddr(wb_reg_addr), .wdata(wb_data_out), .rdata1(rdata1), .rdata2(rdata2),
                    .regs_o(regs), .a0_data(a0));

    if_id IF_ID(.clk(clock), .reset(reset), .stall(stall), .i_inst(inst_r_data), .i_inst_addr(inst_r_addr), .i_pc(inst_r_addr), .i_badvaddr(id_badvaddr), .i_excode(id_excode), .i_except_ena(id_except_ena), .flush_if_id(flush_if_id), .flush(flush), .i_inst_r_valid(inst_r_valid), .keep(keep),
                .o_inst(if_id_o_inst), .o_inst_addr(if_id_o_inst_addr), .o_pc(if_id_pc),
                .o_badvaddr(id_badvaddr), .o_excode(id_excode), .o_except_ena(id_except_ena), .o_inst_r_valid(id_inst_r_valid));

    decode DECODE(.clk(clock), .reset(reset), .inst(if_id_o_inst), .inst_addr(if_id_o_inst_addr), .rdata1(rdata1), .rdata2(rdata2), .exe_out_addr(exe_reg_addr), .exe_out(exe_data), .mem_out_addr(mem_reg_addr),
                  .mem_out_1(mem_data1), .mem_out_2(mem_data_o), .exe_write_to_regfile(exe_write_to_regfile), .mem_write_to_regfile(mem_write_to_regfile), .exe_mem_to_regfile(exe_mem_to_regfile), .mem_mem_to_regfile(mem_mem_to_regfile),
                  .i_excode(id_excode), .i_except_ena(id_except_ena),
                  .write_to_mem(id_write_to_mem), .write_to_regfile(id_write_to_regfile), .reg_addr(id_reg_addr), .ALUControl(id_ALUControl), .b_j_pc(b_j_pc), .pcsource(id_pcsource),
                  .sext_imm(id_sext_imm), .aluimm(id_aluimm), .data1(id_data1), .data2(id_data2), .is_jump(id_is_jump), .mem_control(id_mem_control), .mem_to_regfile(id_mem_to_regfile), .csr(id_csr), .csr_wdata(id_csr_wdata),
                  .csr_control(id_csr_control), .o_excode(id_o_excode), .o_except_ena(id_o_except_ena), .flush_if_id(flush_if_id), .ret(id_o_ret), .shift(id_o_shift), .shamt_ext(id_o_shamt_ext));
    
    id_exe ID_EXE(.clk(clock), .reset(reset), .stall(stall), .i_write_to_mem(id_write_to_mem), .i_write_to_regfile(id_write_to_regfile), .i_reg_addr(id_reg_addr), .i_ALUControl(id_ALUControl),
                  .i_sext_imm(id_sext_imm), .i_aluimm(id_aluimm), .i_data1(id_data1), .i_data2(id_data2), .i_is_jump(id_is_jump), .i_mem_control(id_mem_control), .i_mem_to_regfile(id_mem_to_regfile),
                  .i_pc(if_id_pc), .i_inst(if_id_o_inst), .i_csr(id_csr), .i_csr_wdata(id_csr_wdata), .i_csr_control(id_csr_control), .i_badvaddr(id_badvaddr), .i_excode(id_o_excode), .i_except_ena(id_o_except_ena),
                  .flush(flush), .i_ret(id_o_ret), .i_inst_r_valid(id_inst_r_valid), .i_shift(id_o_shift), .i_shamt_ext(id_o_shamt_ext),
                  .o_write_to_mem(exe_write_to_mem), .o_write_to_regfile(exe_write_to_regfile), .o_reg_addr(exe_reg_addr), .o_ALUControl(exe_ALUControl), .o_sext_imm(exe_sext_imm),
                  .o_aluimm(exe_aluimm), .o_data1(exe_data1), .o_data2(exe_data2), .o_is_jump(exe_is_jump), .o_mem_control(exe_mem_control), .o_mem_to_regfile(exe_mem_to_regfile),
                  .o_pc(exe_pc), .o_inst(exe_inst), .o_csr(exe_csr), .o_csr_wdata(exe_csr_wdata), .o_csr_control(exe_csr_control), .o_badvaddr(exe_badvaddr), .o_excode(exe_excode), .o_except_ena(exe_except_ena), .o_ret(exe_ret), .o_inst_r_valid(exe_inst_r_valid),
                  .o_shift(exe_shift), .o_shamt_ext(exe_shamt_ext));
    
    exe EXE(.sext_imm(exe_sext_imm), .aluimm(exe_aluimm), .data1(exe_data1), .data2(exe_data2), .is_jump(exe_is_jump), .ALUControl(exe_ALUControl), .csr_control(exe_csr_control),
            .csr_wdata(exe_csr_wdata), .csr_data(csr_data), .i_pc(exe_pc), .shift(exe_shift), .shamt_ext(exe_shamt_ext), .data(exe_data), .csr_data_res(exe_o_csr_data_res), .write_ena(exe_o_write_ena));
    
    exe_mem EXE_MEM(.clk(clock), .reset(reset), .stall(stall), .i_write_to_mem(exe_write_to_mem), .i_write_to_regfile(exe_write_to_regfile), .i_reg_addr(exe_reg_addr), .i_data1(exe_data), .i_data2(exe_data2),
                    .i_mem_control(exe_mem_control), .i_mem_to_regfile(exe_mem_to_regfile), .i_pc(exe_pc), .i_inst(exe_inst),
                    .i_badvaddr(exe_badvaddr), .i_excode(exe_excode), .i_except_ena(exe_except_ena), .flush(flush), .i_ret(exe_ret), .i_inst_r_valid(exe_inst_r_valid),
                    .o_write_to_mem(mem_write_to_mem), .o_write_to_regfile(mem_write_to_regfile), .o_reg_addr(mem_reg_addr), .o_data1(mem_data1), .o_data2(mem_data2),
                    .o_mem_control(mem_mem_control), .o_mem_to_regfile(mem_mem_to_regfile), .o_pc(mem_pc), .o_inst(mem_inst),
                    .o_badvaddr(mem_badvaddr), .o_excode(mem_excode), .o_except_ena(mem_except_ena), .o_ret(mem_ret), .o_inst_r_valid(mem_inst_r_valid));
    
    CLINT clint(.clk(clock), .reset(reset), .wdata(time_wdata), .mtimecmp_ena(mtimecmp_ena), .mtime_ena(mtime_ena), .mtime_int(mem_mtime_int), .mtime_data(mtime_data), .mtimecmp_data(mtimecmp_data));

    mem MEM(.mem_data_i(data_r_data), .mem_addr(mem_data1), .mem_control(mem_mem_control), .i_badvaddr(mem_badvaddr), .i_excode(mem_excode), .data_w_valid(data_w_valid), .data_r_valid(data_r_valid), .mem_wdata(mem_data2),
            .i_except_ena(mem_except_ena), .mem_data_o(mem_data_o), .mem_mask(mem_mask), .data_r_ena(data_r_ena), .data_w_ena(data_w_ena), .data_w_addr(data_w_addr), .o_badvaddr(mem_o_badvaddr), .o_excode(mem_o_excode), .o_except_ena(mem_wb_except_ena), .stall_o(stall_from_mem),
            .data_w_data(data_w_data), .data_r_addr(data_r_addr), .mtime_ena(mtime_ena), .mtimecmp_ena(mtimecmp_ena), .time_wdata(time_wdata), .mtime_data(mtime_data), .mtimecmp_data(mtimecmp_data));

    mem_wb MEM_WB(.clk(clock), .reset(reset), .stall(stall), .i_write_to_regfile(mem_write_to_regfile), .i_mem_to_regfile(mem_mem_to_regfile), .i_reg_addr(mem_reg_addr), .i_alu_data(mem_data1), .i_mem_data(mem_data_o),
                  .i_inst(mem_inst), .i_pc(mem_pc), .i_badvaddr(mem_o_badvaddr), .i_excode(mem_o_excode), .i_except_ena(mem_wb_except_ena), .flush(flush), .i_ret(mem_ret), .i_inst_r_valid(mem_inst_r_valid), .i_mtime_int(mem_mtime_int),
                  .o_write_to_regfile(wb_write_to_regfile), .o_mem_to_regfile(wb_mem_to_regfile), .o_reg_addr(wb_reg_addr), .o_alu_data(wb_alu_data), 
                  .o_mem_data(wb_mem_data), .o_pc(wb_pc), .o_inst(wb_inst), .o_badvaddr(wb_badvaddr), .o_excode(wb_excode), .o_except_ena(wb_except_ena), .o_ret(wb_ret), .o_inst_r_valid(wb_inst_r_valid), .o_mtime_int(csr_mtime_int));
    
    wb WB(.mem_to_regfile(wb_mem_to_regfile), .alu_data(wb_alu_data), .mem_data(wb_mem_data), .data_out(wb_data_out));

    csr CSR(.clk(clock), .reset(reset), .csr_wdata(exe_o_csr_data_res), .i_csr(exe_csr), .write_ena(exe_o_write_ena), .except_ena(wb_except_ena), .i_addr(wb_pc), .i_badvaddr(wb_badvaddr), .i_excode(wb_excode), .badinst(wb_inst),
            .ret(wb_ret), .mtime_int(csr_mtime_int), .o_csr_data(csr_data), .mtvec_pc(mtvec_pc), .epc(epc), .mstatus_data(csr_mstatus), .mtvec_data(csr_mtvec), .mepc_data(csr_mepc), .mcause_data(csr_mcause), .mie_data(csr_mie), .mip_data(csr_mip), .mscratch_data(csr_mscratch),
            .sstatus_data(csr_sstatus));

    ctrl CTRL(.clk(clock), .reset(reset), .except_ena(wb_except_ena), .mtvec_pc(mtvec_pc), .epc(epc), .ret(wb_ret), .stall_from_if(stall_from_if), .stall_from_mem(stall_from_mem), .new_pc(new_pc), .flush(flush), .stall(stall), .inst_r_valid(inst_r_valid),
              .keep(keep));

    delay_stage DS(.clk(clock), .reset(reset), .i_pc(wb_pc), .i_inst(wb_inst), .i_write_to_regfile(wb_write_to_regfile), .i_reg_addr(wb_reg_addr), .i_data_out(wb_data_out), .i_inst_r_valid(wb_inst_r_valid), .i_mstatus(csr_mstatus),
                   .i_mtvec(csr_mtvec), .i_mepc(csr_mepc), .i_mcause(csr_mcause), .i_mie(csr_mie), .i_mip(csr_mip), .o_pc(delay_pc), .o_inst(delay_inst),
                   .o_write_to_regfile(delay_write_to_regfile), .o_reg_addr(delay_reg_addr), .o_data_out(delay_data_out), .o_inst_r_valid(delay_inst_r_valid), .o_mstatus(delay_mstatus), .o_mtvec(delay_mtvec), .o_mepc(delay_mepc),
                   .o_mcause(delay_mcause), .o_mie(delay_mie), .o_mip(delay_mip));
                   
endmodulemodule pc(
    input clk,
    input reset,
    input [5:0] stall,
    input [63:0] b_j_pc,
    input pcsource,
    input [63:0] new_pc,
    input flush,
    input ret,
    input flush_if_id,
    input keep,

    output reg [63:0] o_inst_addr,
    output [63:0] o_badvaddr,
    output [63:0] o_excode,
    output o_except_ena
);

    always @(posedge clk) begin
        if(reset) begin
            o_inst_addr <= 64'h0000000080000000;
        end else if(flush | ret) begin
            o_inst_addr <= new_pc;
        end else if(keep) begin
            o_inst_addr <= o_inst_addr;
        end else if(stall[0] == 1'b0) begin
            if(pcsource) begin
                o_inst_addr <= b_j_pc;
            end else begin
                o_inst_addr <= o_inst_addr + 64'd4;
            end
        end
    end

    assign o_badvaddr = o_inst_addr[1:0] == 2'b00 ? 64'd0 : o_inst_addr;
    assign o_excode = o_inst_addr[1:0] == 2'b00 ? 64'd0 : {1'b0, 63'd0};
    assign o_except_ena = o_inst_addr[1:0] == 2'b00 ? 1'b0 : 1'b1;

endmodule
module ysyx_210191_regfile(
    input clk,
    input reset,
    input en,
    input [4:0] raddr1,
    input [4:0] raddr2,
    input [4:0] waddr,
    input [63:0] wdata,
    
    output [63:0] rdata1,
    output [63:0] rdata2,
    output [63:0] a0_data,
    output wire [63:0] regs_o[0:31]
);

    reg [63:0] regfile[0:31];
    
    assign rdata1 = raddr1 == 5'b00000 ? 64'd0 : regfile[raddr1];
    assign rdata2 = raddr2 == 5'b00000 ? 64'd0 : regfile[raddr2];
    assign a0_data = regfile[64'd10];

    always@(posedge clk) begin
        if(reset) begin
            integer i;
            for(i = 0;i < 32;i = i + 1) begin
                regfile[i] <= 64'd0;
            end
        end else if(en && (waddr != 5'b00000)) begin
            regfile[waddr] <= wdata;
        end
    end

    genvar i;
	generate
		for (i = 0; i < 32; i = i + 1) begin
			assign regs_o[i] = regfile[i];
		end
	endgenerate

endmodule
`define AXI_TOP_INTERFACE(name) io_memAXI_0_``name
module ysyx_210191_SimTop(
    input                               clock,
    input                               reset,

    input  [63:0]                       io_logCtrl_log_begin,
    input  [63:0]                       io_logCtrl_log_end,
    input  [63:0]                       io_logCtrl_log_level,
    input                               io_perfInfo_clean,
    input                               io_perfInfo_dump,

    output                              io_uart_out_valid,
    output [7:0]                        io_uart_out_ch,
    output                              io_uart_in_valid,
    input  [7:0]                        io_uart_in_ch,

    input                               `AXI_TOP_INTERFACE(aw_ready),
    output                              `AXI_TOP_INTERFACE(aw_valid),
    output [63:0]                       `AXI_TOP_INTERFACE(aw_bits_addr),
    output [2:0]                        `AXI_TOP_INTERFACE(aw_bits_prot),
    output [4:0]                        `AXI_TOP_INTERFACE(aw_bits_id),
    output                              `AXI_TOP_INTERFACE(aw_bits_user),
    output [7:0]                        `AXI_TOP_INTERFACE(aw_bits_len),
    output [2:0]                        `AXI_TOP_INTERFACE(aw_bits_size),
    output [1:0]                        `AXI_TOP_INTERFACE(aw_bits_burst),
    output                              `AXI_TOP_INTERFACE(aw_bits_lock),
    output [3:0]                        `AXI_TOP_INTERFACE(aw_bits_cache),
    output [3:0]                        `AXI_TOP_INTERFACE(aw_bits_qos),
    
    input                               `AXI_TOP_INTERFACE(w_ready),
    output                              `AXI_TOP_INTERFACE(w_valid),
    output [63:0]                       `AXI_TOP_INTERFACE(w_bits_data)         [3:0],
    output [7:0]                        `AXI_TOP_INTERFACE(w_bits_strb),
    output                              `AXI_TOP_INTERFACE(w_bits_last),
    
    output                              `AXI_TOP_INTERFACE(b_ready),
    input                               `AXI_TOP_INTERFACE(b_valid),
    input  [1:0]                        `AXI_TOP_INTERFACE(b_bits_resp),
    input  [3:0]                        `AXI_TOP_INTERFACE(b_bits_id),
    input                               `AXI_TOP_INTERFACE(b_bits_user),

    input                               `AXI_TOP_INTERFACE(ar_ready),
    output                              `AXI_TOP_INTERFACE(ar_valid),
    output [63:0]                       `AXI_TOP_INTERFACE(ar_bits_addr),
    output [2:0]                        `AXI_TOP_INTERFACE(ar_bits_prot),
    output [3:0]                        `AXI_TOP_INTERFACE(ar_bits_id),
    output                              `AXI_TOP_INTERFACE(ar_bits_user),
    output [7:0]                        `AXI_TOP_INTERFACE(ar_bits_len),
    output [2:0]                        `AXI_TOP_INTERFACE(ar_bits_size),
    output [1:0]                        `AXI_TOP_INTERFACE(ar_bits_burst),
    output                              `AXI_TOP_INTERFACE(ar_bits_lock),
    output [3:0]                        `AXI_TOP_INTERFACE(ar_bits_cache),
    output [3:0]                        `AXI_TOP_INTERFACE(ar_bits_qos),
    
    output                              `AXI_TOP_INTERFACE(r_ready),
    input                               `AXI_TOP_INTERFACE(r_valid),
    input  [1:0]                        `AXI_TOP_INTERFACE(r_bits_resp),
    input  [63:0]                       `AXI_TOP_INTERFACE(r_bits_data)         [3:0],
    input                               `AXI_TOP_INTERFACE(r_bits_last),
    input  [3:0]                        `AXI_TOP_INTERFACE(r_bits_id),
    input                               `AXI_TOP_INTERFACE(r_bits_user)
);

    wire aw_ready;
    wire aw_valid;
    wire [63:0] aw_addr;
    wire [2:0] aw_prot;
    wire [3:0] aw_id;
    wire aw_user;
    wire [7:0] aw_len;
    wire [2:0] aw_size;
    wire [1:0] aw_burst;
    wire aw_lock;
    wire [3:0] aw_cache;
    wire [3:0] aw_qos;
    wire [3:0] aw_region;

    wire w_ready;
    wire w_valid;
    wire [63:0] w_data;
    wire [7:0] w_strb;
    wire w_last;
    wire w_user;
    
    wire b_ready;
    wire b_valid;
    wire [1:0] b_resp;
    wire [3:0] b_id;
    wire b_user;

    wire ar_ready;
    wire ar_valid;
    wire [63:0] ar_addr;
    wire [2:0] ar_prot;
    wire [3:0] ar_id;
    wire ar_user;
    wire [7:0] ar_len;
    wire [2:0] ar_size;
    wire [1:0] ar_burst;
    wire ar_lock;
    wire [3:0] ar_cache;
    wire [3:0] ar_qos;
    wire [3:0] ar_region;
    
    wire r_ready;
    wire r_valid;
    wire [1:0] r_resp;
    wire [63:0] r_data;
    wire r_last;
    wire [3:0] r_id;
    wire r_user;

    assign ar_ready                                 = `AXI_TOP_INTERFACE(ar_ready);
    assign `AXI_TOP_INTERFACE(ar_valid)             = ar_valid;
    assign `AXI_TOP_INTERFACE(ar_bits_addr)         = ar_addr;
    assign `AXI_TOP_INTERFACE(ar_bits_prot)         = ar_prot;
    assign `AXI_TOP_INTERFACE(ar_bits_id)           = ar_id;
    assign `AXI_TOP_INTERFACE(ar_bits_user)         = ar_user;
    assign `AXI_TOP_INTERFACE(ar_bits_len)          = ar_len;
    assign `AXI_TOP_INTERFACE(ar_bits_size)         = ar_size;
    assign `AXI_TOP_INTERFACE(ar_bits_burst)        = ar_burst;
    assign `AXI_TOP_INTERFACE(ar_bits_lock)         = ar_lock;
    assign `AXI_TOP_INTERFACE(ar_bits_cache)        = ar_cache;
    assign `AXI_TOP_INTERFACE(ar_bits_qos)          = ar_qos;
    
    assign `AXI_TOP_INTERFACE(r_ready)              = r_ready;
    assign r_valid                                  = `AXI_TOP_INTERFACE(r_valid);
    assign r_resp                                   = `AXI_TOP_INTERFACE(r_bits_resp);
    assign r_data                                   = `AXI_TOP_INTERFACE(r_bits_data)[0];
    assign r_last                                   = `AXI_TOP_INTERFACE(r_bits_last);
    assign r_id                                     = `AXI_TOP_INTERFACE(r_bits_id);
    assign r_user                                   = `AXI_TOP_INTERFACE(r_bits_user);

    assign aw_ready                                 = `AXI_TOP_INTERFACE(aw_ready);
    assign `AXI_TOP_INTERFACE(aw_valid)             = aw_valid;
    assign `AXI_TOP_INTERFACE(aw_bits_addr)         = aw_addr;
    assign `AXI_TOP_INTERFACE(aw_bits_prot)         = aw_prot;
    assign `AXI_TOP_INTERFACE(aw_bits_id)           = aw_id;
    assign `AXI_TOP_INTERFACE(aw_bits_user)         = aw_user;
    assign `AXI_TOP_INTERFACE(aw_bits_len)          = aw_len;
    assign `AXI_TOP_INTERFACE(aw_bits_size)         = aw_size;
    assign `AXI_TOP_INTERFACE(aw_bits_burst)        = aw_burst;
    assign `AXI_TOP_INTERFACE(aw_bits_lock)         = aw_lock;
    assign `AXI_TOP_INTERFACE(aw_bits_cache)        = aw_cache;
    assign `AXI_TOP_INTERFACE(aw_bits_qos)          = aw_qos;
    
    assign w_ready                                  = `AXI_TOP_INTERFACE(w_ready);
    assign `AXI_TOP_INTERFACE(w_valid)              = w_valid;
    assign `AXI_TOP_INTERFACE(w_bits_data)[0]       = w_data;
    assign `AXI_TOP_INTERFACE(w_bits_last)          = w_last;
    assign `AXI_TOP_INTERFACE(w_bits_strb)          = w_strb;

    assign `AXI_TOP_INTERFACE(b_ready)              = b_ready ;
    assign b_valid                                  = `AXI_TOP_INTERFACE(b_valid);
    assign b_resp                                   = `AXI_TOP_INTERFACE(b_bits_resp);
    assign b_id                                     = `AXI_TOP_INTERFACE(b_bits_id);
    assign b_user                                   = `AXI_TOP_INTERFACE(b_bits_user);

    wire flush;
    wire data_r_valid;
    wire data_w_valid;
    wire [63:0] data_r_data;
    wire [31:0] inst_r_data;
    wire inst_r_valid;
    wire inst_r_ena;
    wire [63:0] inst_r_addr;
    wire [63:0] data_w_addr;
    wire [63:0] data_w_data;
    wire data_w_ena;
    wire data_r_ena;
    wire [63:0] data_r_addr;
    wire [7:0] mem_mask;

  mycpu CPU(
      .clock(clock), 
      .reset(reset), 
      .data_r_valid(data_r_valid), 
      .data_w_valid(data_w_valid), 
      .data_r_data(data_r_data), 
      .inst_r_data(inst_r_data), 
      .inst_r_valid(inst_r_valid),
      .inst_r_ena(inst_r_ena), 
      .inst_r_addr(inst_r_addr), 
      .data_w_addr(data_w_addr), 
      .data_w_data(data_w_data), 
      .data_w_ena(data_w_ena), 
      .data_r_ena(data_r_ena), 
      .data_r_addr(data_r_addr), 
      .mem_mask(mem_mask),
      .flush(flush));

    axi4_crtl AXI(
      .ACLK(clock), 
      .ARESETn(reset),
      .flush(flush), 
      .inst_r_ena(inst_r_ena), 
      .inst_addr(inst_r_addr), 
      .inst_r(inst_r_data),
      .data_r_ena(data_r_ena), 
      .data_w_ena(data_w_ena), 
      .data_w(data_w_data), 
      .data_addr(data_r_addr), 
      .data_w_addr(data_w_addr),
      .data_w_mask(mem_mask),
      .wlast_i(1'b1), 
      .data_r(data_r_data), 
      .ARID(ar_id),
      .ARADDR(ar_addr), 
      .ARLEN(ar_len),
      .ARSIZE(ar_size),
      .ARBURST(ar_burst),
      .ARLOCK(ar_lock),
      .ARCACHE(ar_cache),
      .ARPROT(ar_prot),
      .ARQOS(ar_qos),
      .ARREGION(ar_region),
      .ARVALID(ar_valid), 
      .ARREADY(ar_ready), 
      .RID(r_id), 
      .RDATA(r_data), 
      .RVALID(r_valid), 
      .RREADY(r_ready), 
      .RLAST(r_last),
      .RRESP(r_resp),
      .AWID(aw_id), 
      .AWADDR(aw_addr), 
      .AWLEN(aw_len),
      .AWSIZE(aw_size),
      .AWBURST(aw_burst),
      .AWLOCK(aw_lock),
      .AWCACHE(aw_cache),
      .AWPROT(aw_prot),
      .AWQOS(aw_qos),
      .AWREGION(aw_region),
      .AWVALID(aw_valid), 
      .AWREADY(aw_ready), 
      .WDATA(w_data), 
      .WSTRB(w_strb), 
      .WVALID(w_valid), 
      .WREADY(w_ready),
      .WLAST(w_last), 
      .BID(b_id), 
      .BVALID(b_valid), 
      .BREADY(b_ready),
      .BRESP(b_resp),
      .data_r_valid(data_r_valid),
      .data_w_valid(data_w_valid),
      .inst_r_valid(inst_r_valid));
endmodulemodule wb(
    input mem_to_regfile,
    input [63:0] alu_data,
    input [63:0] mem_data,

    output [63:0] data_out
);

    assign data_out = mem_to_regfile ? mem_data : alu_data;

endmodule

endmodule